1 Welcome to R!

R is a versatile coding language for data science, with a wonderful community supporting it. Here’s a short list of some of the things that make R great.

  1. Free and open source It’s a free and open source programming language and environment for statistical computing, machine learning, and graphics.

  2. Reproducibility and Reporting writing reproducible reports is now easier than ever thanks to packages like knitr and R Markdown.

  3. RStudio RStudio is a powerful Interactive Development Environment that has made learning R and using R much easier. With options for workflow and project management.

  4. Graphics. R can be used to make great data graphics, with packages like ggplot2 helping users make graphics in an intuitive way.

  5. R Packages and Community With over 15,000 packages on CRAN alone, there’s pretty much a package to do anything. The greater R community has also expanded tremendously over time, bringing in new users and pushing R to be useful in more applications. Each year there are thousands of meetups, conferences, seminars, and workshops on R all around the world.

2 Objectives:

  • Familiarise yourself with RStudio and R Notebooks, which is what we’ll use to interact with R.

  • Learn about the simple data structures in R: object, vector, and data frame.

  • Explore R’s basic data types = integer, character, numeric, etc.

  • Learn to read data into R.

  • Introduction to data wrangling using the tidyverse set of metapackages.

  • Use the tidyverse verbs to explore the gapminder data set which includes statistics for countries around the world including life expectancy, population, and GDP per capita.

  • Learn to merge datasets using left_join.

  • Create meaningful visualisations of the data using ggplot2.

  • Learn where to go for help.

3 RStudio and RNotebooks

First let’s set it so that our notebook shows up in our viewer.

  • Click on the gear icon next to Knit on the menu. Select Preview in Viewer Pane.

  • Now click on the little arrow next to Knit and select “Knit to HTML”.

3.1 RStudio

In this training we will be using RStudio. RStudio is an interactive development environment (IDE) for R and is broken down into various panels for our convenience.

  • Q1: script, data, command to run script
    • This is the panel you’re reading this tutorial in. It contains the script editor where we can create and edit R Notebook files, among other files.
  • Q2: console
    • This is the Console Panel where R code is passed to and executed.
  • Q3: environment
    • The environment tab keeps track of variables we’ve created in this workspace.
  • Q4: files, plots, packages, help
    • This is a multi-purpose panel which contains:
      • Files: A basic file explorer,
      • Plots: Where plots can be rendered,
      • Packages: install and import libraries into R,
      • Help: Explorer for Documentation of functions and libraries,
      • Viewer: View local web content e.g. Shiny app.

3.1.1 Settings

Some people like RStudio to remember stuff from session to session. However, this can be dangerous as previous work and packages can interfere with current code and make your code more breakable. To avoid this, it is recommended that you change two settings in RStudio.

Locate Preferences (On Windows, this is in the Tools->Global Options menu; on a Mac, this is in the RStudio menu). In the General tab, uncheck “Restore .RData…” and select “never” for “Save workspace…”

3.2 R Notebooks

R Notebooks give the opportunity to combine code and description in a single human-readable notebook. You can conduct analysis and give interpretation side-by-side! This means that your entire analytical approach can be documented together, from the raw data to the analysis and finally results and conclusions.

3.2.1 Where the code goes…

We will be entering the R code into these blocks:

[1] "code goes here!"

We can run the block of code using the play button on the right. We can also run this block of code with all previous blocks of code with the downwards facing play button in the middle.

In some places I have added additional arguments to the code chunk (e.g. eval = FALSE) so that something is not evaluated in order for the html file to compile. See the example below:

Feel free to change this by simply removing the , eval = FALSE especially as you update the document. However, note that if there are any code errors left, the html file will not compile.

3.2.2 Adding comments and other helpful shortcuts

  • You can add comments within your R code chunk using #.

    • Your comments can be notes for yourself, or explanation of what the code is doing for someone to follow.
    • You can also comment out code you don’t want to be immediately run.
  • You can comment or uncomment code using Ctrl + Shift + C.

  • You can run a line of code by placing your cursor anywhere on the line and using Ctrl + Enter. This will execute the line of code and move the cursor to the next line.

4 Basics

4.1 Objects

Let’s start by making an assignment and inspecting the object we created.

All R statements where you create objects by making an ‘assignment’, take the form:

  • object_name <- value

You can think of objects as storage containers for values. An object is created using the operator <-. It can be a pain to type <-, but don’t be tempted to use = as this has another specific use in the R language.

4.1.1 Naming objects

You can name your objects anything. You can use letters, numbers, periods and underscores. You just can’t start names with a dot or a number 1,2,3... and your name cannot contain other characters such as a comma or a space.

Try running the following lines of code. Try uncommenting the code # this_doesn't_work <- 10*5 by clicking on the line and using Ctrl + Shift + C.

4.1.2 Make your object names easy to read

It is useful for future you and your collaborators to name your objects something that is reasonable and describes what the object contains. To make your object names easy to read it is useful to adopt a convention for demarcating words in names.

4.1.3 Using Tab Completion to Complete Object Names

Make a new object

Sometimes to make our object names readable we use long names that can be labourious to type. Luckily, RStudio has a handy completion facility.

Start by typing the first few letters of a_very... in the code chunk below and type TAB to complete the name.

4.1.4 R is case-sensitive and doesn’t like typos

Let’s try inspecting the object again.

R is very sensitive to both case and spelling mistakes and won’t run unless things are spelled correctly and are in the right case. If you get an error, check your spelling! More than 80% of the time, this is likely the cause of your error!

4.2 Vectors

A vector is a 1-dimensional ordered collection of elements, all of the same type. It is the fundamental data structure in R with a lot of useful properties.

We can extract an element from a vector by referencing its position. Let’s make a new vector called character_vector using the function c() which can be used to c()ombine elements.

4.2.1 Creating a vector with c()

Notice that when we specify words or characters, we use "".

4.2.2 Check the structure of the vector using str()

R is able to recognise, thanks to the "" around our text that the vector contains a character string chr.

4.2.3 Check the length of a vector using length()

4.2.4 Extract multiple consecutive elements using :.

4.2.5 Replace elements using <-

Try replacing the 4th element with your name:

4.2.6 Define a numeric vector

The same method used to extract information works for any type of vector. Here we can define a new vector numeric_vector containing the numbers 1, 2, 3, 4, and 5.

4.2.7 Check the structure using str()

Because we have specified whole numbers, R can either classify the vector as and integer int or as numeric num.

4.2.8 Extract the first two elements

4.2.9 Extract non-consecutive elements using c()

Trying uncommenting and running the line below:

Note that we can only select the 1 and 3 or 1, 3, and 4 elements using c().

4.2.10 Changing the structure of a vector

Let’s make a second numeric vector.

  • You’ll notice that now when we check the structure, the vector is numeric (num). This is because we now have a number with a decimal place.

  • R is what is known in computer science as a dynamically typed language. R doesn’t require you to set the data type when you create a vector, instead it figures out what the best data type is for the object you are creating - numeric, character, factor, logical, etc.

  • However, sometimes the data type you want to work with, and the one R infers are not the same. You can change the data type using a range of in-built functions that enable you to convert data from one type to another.

4.2.10.1 The as. functions

A useful set of functions are the as. functions, which take the form as.<structure>. We can use this to specify the structure of our numeric vector to be numeric.

The structure of vectors becomes important when we use it to analyse different things.

  • Note that now character_vector is now classed as a factor Factor with 4 levels: “ET”, “Home”, “Laurie”, and “Phone”.

  • When you create a factor it uses an integer code to represent each level. So that “ET” is both “ET” and 1, “Home” is both “Home” and 2. You’ll notice that it automatically takes the alphabetic order when determining the factor levels. This means that even though “Phone” occurs 2nd in our character vector, it gets the integer code: 4. This is just a detail now, but becomes important in plotting, especially if you want to change the order in which your factors are plotted.

  • Factors are especially useful if we want to group data by a factor (e.g. country) for counting or summarising. For instance, “Home” and “Phone” each occur twice, whereas “Laurie” and “ET” each only occur once.

4.2.11 Vectorised Language

Vectors aren’t just containers for homogeneous data. As R is a vectorised language, this means operations are applied to each element of the vector automatically, without the need to loop through the vector.

This is powerful as at a low-level as computer chips are generally optimised for these types of calculations SIMD.

Let’s look at some examples

4.2.11.1 Multiply and Exponentiate Numeric Vectors

You can also multiply, divide, add, and subtract vectors of the same length.

4.2.11.2 Divide vectors of the same length

4.2.11.3 Subtract or Add vectors of the same length

What happens when you run the following line of code?

4.2.12 Exercises

Fill in the code chunks to answer the following questions

  1. Take the last two elements of the numeric vector
  1. Take the first and last elements of the character_vector.

Hint: you can use length() to find out how many elements there are in the character vector.

  1. Divide the numeric_vector by 3
  1. Multiple the numeric_vector by the new vector ‘y’
  1. Why do the following lines of code not work?

5 CRAN, library, packages, and functions

So far, we’ve seen R’s capabilities as a large calculator and also as a place for storing objects and vectors. However, it is much much more than that! One of the things that makes R amazing is the open source community surrounding it.

The R community which is made up of academics, statisticians, social and political scientists, economists, and data scientists to name a few, are responsible for authoring a wide variety of packages (>15,000) that can do a wide range of data manipulation, visualisation, and analysis tasks.

To get your head around what CRAN, library, packages, and functions are I find it helpful to think of books.

5.1 CRAN

CRAN stands for the Comprehensive R Archive Network. It’s like the R equivalent of the British Library or Library of Congress. It holds a copy of every package (book) and all the versions of R.

5.2 Library

On your computer you’ll have a local library with copies of the packages you’ve installed from CRAN (your home office book shelf).

5.2.1 What’s on your bookshelf?

  • Click on the ‘Packages’ tab in the lower right hand panel (Q4 from before). You can see what packages are in your library, a short description of what they do, and the package version.

  • The packages that are loaded have a check mark in the box on the left. As before, there are several packages that are automatically loaded each time you start an R session, e.g. base package.

  • Although it is possible to load and install your packages from here, I recommend using the functions shown below instead. This way, someoneelse or future you knows exactly what packages they need to run the analyses.

  • You should load the packages you will use at the top of your script, so that future you or your colleague knows what needs to be installed/loaded.

5.2.2 Installing Packages on a Personal Computer

  • A package needs to be installed only once and requires an internet connection which allows your computer to communicate with the CRAN server.

  • You may wish to install a package with the additional argument: dependencies = TRUE, this will also install any packages that the package depends on.

  • On your personal computer, you can install a package to your local library from CRAN by uncommenting and running the following:

However, if you are on a government laptop without elevated access rights, read further…

5.2.3 Installing Packages on a Government Computer

  • On your government laptop, you will need to put in a Service Desk Software Request for any packages you want installed.

  • As a standard user, you are unable to run R packages that you download as it installs them to your Documents folder. Because of restrictions on the government laptops, it is then unable to run the package from this location because the DLL files it contains are blocked.

  • As a result, the R installation often comes with many of the packages you’ll need pre-installed. For any other packages you wish to install, you can put in a Service Desk request.

5.2.4 Errors Installing Packages to a Government Computer

If you do install packages yourself, it is highly likely that you will get this error if you install packages and load them from the internet.

“Error: package or namespace load failed for ‘ggplot2’ in inDL(x, as.logical(local), as.logical(now), …): unable to load shared object ‘C:/Users/l-baker/Documents/R/win-library/3.6/rlang/libs/x64/rlang.dll’: LoadLibrary failure: This program is blocked by group policy. For more information, contact your system administrator.”

If you do try to install packages and if you get the above error you can fix it by deleting your R folder from Documents. R will then return to looking for packages that come supplied with your department’s R distribution.

5.2.5 Loading packages

In order to use the package you need to load it to your workspace. This needs to be done each time you start a new RStudio session or project. Think of it as taking the book you will use off your book shelf to place next to you on the desk.

In this case, tidyverse is a meta-package, which actually contains several individual packages including dplyr, forcats, etc., but more on those later. The tidyverse metapackage is in your library already so we can simply make a call to load them.

Alas, there are not enough names to make each function in every package unique. The “Conflicts” line that is printed tells us that the dplyr function filter will mask the stats package function filter.

If we want to be completely accurate, we can specify the package and function using the following form <package_name>::<function_name>, e.g. dplyr::filter().

If we follow the recipe book analogy, this is like saying we want the lasagna recipe from jamie_oliver::lasagna so that it isn’t confused with the nigella_lawson::lasagna recipe.

5.3 Packages

You can think of a package like a book on a particular subject. Each package is designed to do a specific set of tasks (e.g. data manipulation, implement linear models, draw geographical maps, etc.). Each task is implemented using a function, which is a set of statements organised to complete the task.

5.4 Functions

A function is like a recipe from a book. It is designed to make one specific thing, e.g. cupcakes or steak and kidney pie. The function takes arguments (e.g. ingredients) and then carries out a series of steps where the ingredients are modified, cooked, combined, etc. to create the final recipe.

Some of these arguments will be optional (e.g. add or don’t add cinnamon), whereas other arguments will be required for the function to run (e.g. you can’t make the cake without flour!).

Functions follow the form:

  • functionName(argument1 = value1, argument2 = value2, and so on)

Let’s take a look at some of the built-in functions R has for carrying out basic statistics/analysis, starting with seq().

5.4.1 How functions work: the seq() function

Let’s try using seq() which makes regular sequences of numbers and, while we’re at it, demo more helpful features of RStudio.

  • Type se and hit TAB. A pop up shows you possible completions.
  • Specify seq() by typing more to specify the function or using the up/down arrows to select. Notice the floating help box that pops up to remind you of the function’s arguments.

  • If you want even more help, press F1 as directed to get the full documentation in the help tab of the lower right pane. You can also access the help file for a function by typing ?seq.

  • Now open the parentheses and notice the automatic addition of the closing parenthesis and the placement of cursor in the middle. Type the arguments 1, 10 and hit return. RStudio also exits the parenthetical expression for you.

Let’s take a closer look at the help file for seq().

5.4.1.1 Function help files

Every help file will have a series of sections describing what the function does. I generally focus first on: Description, Usage, Arguments, and Examples.

  • Description

For example, in the helpfile for seq() under Description, it tells us it is a function to “Generate regular sequences”.

  • Usage

We can see that seq() takes the arguments from, to, and by, and the optional arguments length.out and along.with.

  • Arguments

Here, we can find out what these arguments are:

  • from, to: the starting and maximal end values of the sequence.
  • by number: increment of the sequence.

In the code we used above in sequence, we generated a sequence of numbers from 1 to 10. In this case we did not supply a value for by, so it took the default value, which in this case is 1.

5.4.1.2 How are function arguments resolved?

What happens if we try:

And what about:

The above demonstrates something about how R resolves function arguments. You can always specify in name = value form. But if you do not, R attempts to resolve by position.

So above, first it is assumed that we want a sequence from = 1 that goes to = 10. Then if we swap the numbers it is assumed we want to sequence from = 10 that goes to = 1. If we name the arguments explicitly using name = value, the order of the arguments doesn’t matter.

5.4.1.3 Printing objects and viewing your workspace

If we want to store our output in an object and see it in the same line, we can use:

Let’s take a look at our workspace and showcase a function that doesn’t require any arguments.

If you want to remove the vector name y you can use

If you want to remove everything in your workspace you can use:

You may want to do this at the end of an analysis before you start on another project.

6 Data frames and tibbles

Anytime your data is rectangular, spreadsheet-like data, the default data format in R is a data frame. Data frames can hold variables of different types. Where each column of the data, is essentially a vector, such as numeric data (GDP), character data (country name), and categorical information (infected vs. uninfected).

Data frames are extremely useful and many functions are set up to take a data frame for the data = argument. The tidyverse packages, which include dplyr and ggplot2 work with a special type of data frame, called a “tibble”.

6.1 Gapminder Data

Our data comes from the Gapminder foundation, an organization dedicated to educating the public by using data to dispel common myths about the so-called developing world. The dataset we will use is one that has been combined from the gapminder data set from the gapminder package, and the gapminder data set from the dslabs package.

6.2 Reading in the data

Before you read in a data file you want to ask yourself two questions:

  1. What type of file is it?
  2. Where is the file stored?

In this case, we are going to read in a .csv (comma separated value) file called gapminder.csv.

The tidyverse comes with a number of useful functions for reading in data. For some of the most common files you work with you can use:

  • read_csv: reads in a csv file
  • read_excel: from the readxl package reads in an excel file (.xls and .xlsx). Possible to add the sheet number or name you wish to extract. Check out the arguments in the helpfile using ?read_excel.

and much, much, more! If you are looking for another file type I highly recommend checking out this section from Jenny Bryan’s UBC stats course Stat545 Import and Export or looking more generally into the readr package. There are nice options for removing lines of meta data (e.g. rambles at the head of an excel spreadsheet) and other options for messier data frames.

6.2.1 Reading in the data using the read_ functions

The functions for reading in the data take the same basic form

  • First you need to specify the name of the data frame you want to store your data in.

  • Then you specify the file name (file = or in readxl path =) (don’t forget the file format e.g. .csv) and the location where it is stored in quotes.

In this case the file is stored in the folder “data” which is part of the IntroR course master folder you were sent. Here, you’ll notice that we are using a relative path, that is the location of the data is specified in relation to our script file. Relative paths are especially useful because they will work across all operating systems and unlike a “hard path”, e.g. C:/Users/l-baker/repos/The_faculty/IntroR4IntlDev", this relative path will work on anyone’s computer, not just my own!

For a ‘relative path’ to work, we need to get to the right directory (location where our script file is stored). You can do this using the RStudio menu:

  • “Session -> Set Working Directory -> To Source File Location”. In this case this will set the working directory to the location where the script file: “IntroR4IntlDev.Rmd” is stored.

  • Alternatively, you can use setwd("C:/Users/l-baker/repos/The_faculty/IntroR4IntlDev") and give it the file path where your script file is located.

  • To find out where you are you can use the function getwd() which stands for “get working directory”.

6.2.2 Specifying Paths: Good practice

One of the good practices of coding is to never use absolute or “hard paths”. Just because your script tells a colleague what subfolder the data is kept in on your computer, does not help them reproduce the code, especially as a hard path only works for your computer.

The advantage of “relative paths” is that they will work across operating systems and across anyone’s computer. For each project, it is best practice to set up a folder for that project with your script file and subfolders to store the “figures” and the “data”.

In sharing code, you share the whole master folder complete with the figure and data subfolders. Then as long as they set the working directory to the location of your script file, they can run your script with little trouble accessing the figures and data needed from the relative paths specified.

6.3 Exploring the Gapminder Data

The data contains 8 columns

  • country
  • continent
  • year
  • lifeExp. Life expectancy in years.
  • pop. Country population
  • gdpPercap. GDP per capita according to World Bankdev.
  • infant_mortality. Infant deaths per 1000.
  • fertility. Average number of children per woman.

6.3.1 Quick Poll

For each of the three pairs of countries below, which country do you think had the highest infant mortality rates in 2007? Which pairs do you think are the most similar?

  1. Sri Lanka or Turkey

  2. Poland or Malaysia

  3. Pakistan or Vietnam

Which of the two pairs of countries do you think had the highest life expectancy in 2007. Which are the most similar?

  1. South Africa or Yemen

  2. Chile or Hungary

For the two pairs of countries below, which country do you think had the highest gdpPercap in 2007?

  1. Switzerland or Kuwait

  2. Colombia or Nepal

6.4 Getting to know the data

There are several tools to get to know our data.

  • View(): allows us to view the data frame as a spreadsheet.
  • nrow(): tells us the number of rows in our data frame.
  • names(): gives us the names of the columns in our data frame.
  • dim(): tells us the dimensions of our data frame.
  • summary(): give us summary statistics (counts, min, median, mean, max).
  • head(): gives us the first 6 elements of the data.
  • tail(): gives us the last 6 elements of the data.
  • str(): tells us the variable type (e.g. Factor, num (number), int (integer)).
  • unique(): tells us the unique elements of a variable.

6.4.1 Using head() and View()

Let’s take a look at head and View to inspect the data more closely.

From viewing the data we can see that the data contains eight variables: country, continent, year, lifeExp, pop, gdpPercap, infant_mortality, and fertility.

Click “Filter” in the View menu, you can use this similarly to how you would interact with the data in Excel.

Exercise

  1. Using filter, what was the life expectancy in Rwanda in 1952?

  2. Which country had the highest infant mortality rate? What was the year?

6.4.2 Checking the structure of the data using str()

We’ve already used str() to explore our vectors, we can also use it to take a look at our data frame to tell us what type of variables we have.

In this case country and continent are characters, year, lifeExp, pop, gdpPercap, infant_mortality and fertility are numbers.

You’ll notice from the preview that both infant_mortality and fertility have some NAs. NAs are commonly used to show that there is no data for a given year and variable.

One of the first things we are going to do is change the columns country and continent to factors, as we can treat them as categorical variables (i.e. they indicate a category that data belongs to). We can do this using the as.factor function.

*You’ll notice from above that we can select columns by using the dollar sign $.

6.4.3 Exercises

Run the following lines of code to answer the questions below

  1. What are the dimensions of the dataframe? What do each of the numbers refer to?
  1. What are the names of the columns in the data frame?

*Given spelling is so important in R, names() is a handy way to check the names of our columns.

  1. What are the first and last countries in the data frame?
  1. What is the minimum and maximum gdpPercap? How many NAs are there for fertility? How many observations do we have for Africa?
  1. What years are covered in the data frame?
  1. How many countries are in our data frame?

6.5 Extracting Information

Battleship

Whenever I think of R dataframes I think of the game battleship. In battleship, to strike the other opponent’s ships you launch missiles by giving a row and column reference for the location to hit on your opponent’s board.

Data frames are much the same. We can extract an element by specifying the rows and the columns:

  • data_frame[rows, columns]

6.5.1 Selecting a single value

If we wanted to get the first value from the first row and column in the dataframe we could use:

6.5.2 Selecting a whole row

If we wanted the whole first row we could use:

Notice, that if we want to select all columns we simply add a comma and leave the column position blank.

What happens if you run the following?

6.5.3 Selecting specific rows and columns

If we wanted the first 5 rows and the first and third columns we could use:

Remember from before that if we have nonconsecutive positions, we need to use the c() function to combine these positions into a list.

6.5.4 Reference columns by name

We can also reference the column by name:

Why might this be preferred to referencing columns by number?

6.5.5 Exercises

  1. Extract all rows from the column pop and save it in a new object called pop

Hint: look back to how we selected row 1 and all columns.

  1. Extract the 5th row and 6th column from the dataset

Bonus

  1. Extract all the rows for the columns gdpPercap and pop.

Hint: look back to how we selected row 1 and all columns.

  1. Extract rows 5, 20, and 44 from the column lifeExp and save it in a new data frame called sub_lifeExp

6.6 Data subsetting and summarising using dplyr:

So far I’ve shown you the ‘old school’ method for extracting and filtering data. It is useful to know the layout of vectors and dataframes, especially if you end up writing your own for loops or functions in the future.

However, the package, dplyr, has made a lot of data manipulation easier and clearer using verbs to filter and select different elements.

  • select() subsets columns based on their names.
  • filter() subsets rows based on their values.
  • summarise() calculates summary statistics.
  • group_by() groups variable for summarising.
  • mutate() adds new columns that are functions of existing variables.

These verbs can be combined in powerful ways to do some really interesting data manipulation tasks.

6.6.1 select

6.6.1.1 The pipe operator

These verbs can be used by specifying the data frame first, or using the pipe operator %>%. You can think of the the pipe operator as meaning “and then”.

One big advantage of the pipe operator is that it does not change your raw data in any way!

This is really useful because it means you can manipulate your data without having to store new data frames for each step. It also means you never comprimise the original data.

6.6.1.2 Assign your output to a new data frame

You can also assign your output to a new data frame.

6.6.2 Exercises

  1. Run the following line of code, what does the minus do?
  1. Select the columns country, continent and gdpPercap from the data frame.

Extra Credit

  1. Write code for two ways you can select all the columns except for year.

6.6.3 filter

  • filter: subsetting rows

For filtering it is useful to know your set of operators:

Logical Operator Description
< Less Than
<= Less Than or Equal To
> Greater Than
>= Greater Than or Equal To
== Equal To
!= Not Equal To
| Or
& And
%in% c(….) Membership one in a list of elements

(Ignore backslashes in the notebook.)

We can use filter to pick out a particular country. N.B., if we are unsure of names we can always use unique(gapminder$country) to check spellings.

6.6.3.2 Filter rows from a set of matches

We can also use filter to filter rows from a set of countries of interest

6.6.3.3 Combining multiple filters

You can add multiple filters with a comma.

6.6.4 Exercises

  1. What do these lines of code filter the data for?
  1. Filter the data so that you only get entries for countries in “Asia” where the “lifeExp” was below 35
  1. Filter the data so that you only get entries where the gdpPercap was equal to 1000 or less.

Extra Credit

  1. Filter the data using %in% to get the countries “Chile”, “Argentina”, “Uruguay”, and “Peru” and only years greater than or equal to 1992.
  1. Filter the data using != to include the data from all continents apart from Europe.

6.6.5 summarise()

  • summarise() uses existing R functions to calculate summary statistics.

6.6.5.1 Calculate a summary statistic using summarise()

For instance we may wish to calculate the mean lifeExp for all countries:

6.6.5.2 Calculate multiple summary statistics

We can also calculate multiple summary statistics at the same time, separating each new summary variable with a ,. This way we can calculate the mean, min, and max lifeExp for all countries combined:

6.6.7 Exercises:

  1. What does the following bit of code do?
  1. Group the data by country and create two new variables which summarise the minimum and maximum population sizes.

Bonus

  1. Group the data by continent and year. Summarise the maximum and minimum population.

6.6.8 The pipe function %>%

We’ve seen an example of the pipe function %>% in the group_by() example above. The pipe function allows you to combine multiple data wrangling steps which will be carried out in order.

I like to think of the pipe function as the separator of different jobs on an assembly line.

  • Tree (raw data) -> Planks (grouped data) -> Bird House (summarised data)

You begin with your raw data (e.g. tree), it then goes through the pipe to the next station where it is modified in some way (e.g. cut into planks), it can then pass to another station where it can be further modified, and so on and so forth, until Voila! you have your final product (e.g. a bird house).

Let’s say we are interested in calculating the life expectancy in Yemen pre 1980. We can run the following:

We can also combine multiple operators and look at a slice of the data.

slice() chooses rows by their position within the group. In this case we are selecting out the minimum life Expectancy.

We can also see which country had the highest life Expectancy in each year.

6.6.9 Mutate

  • mutate() adds new columns that are functions of existing variables.

Using the verb mutate() we can create a new data column called gdp. In this case the per capita GDP gdpPercap needs to be multiplied by the population pop to get the overall GDP.

This is useful if we want to look at the overall gdp, but it is also a huge number which is difficult to compare among countries in a meaningful way.

6.7 Joining data frames: when one data frame is not enough

It is often the case that our data is spread out over several data frames that we are interested in combining. We can join these data frames together using a variety of join functions from the dplyr package.

Let’s walk through the different types of joins using a simple example.

Let’s say we have two data frames of “tables” we are interesting in joining together: person_table, which contains the information about the employee (Person_ID, Name and Job_ID) and the job_table, which contains information about the job (Job_ID and Job_Name). We can join the two table on the matched ID column Job_ID.

Person Table

Job Table

6.7.1 Inner join:

With an inner join, rows where there’s a match on the join criteria are returned. Unmatched rows are excluded. Don’t worry about the warning message. It is just pointing out that the column Job_ID in the person table has

6.7.2 Left join:

With a left join, you get all rows from the left side of the join even if there are no matching rows on the right side. You only get rows from the right side where there’s a join match to a row on the left.

6.7.3 Right join:

With a right join, you get all the rows from the left side of the join only where there’s a match on the right. You get all rows from the right side of the join even if there are no matching rows on the left.

6.7.4 Full join

With a full join, you get all rows from the left and right hand side, joined where the criteria matches.

6.7.5 Matching the gapminder data to a new data frame uk_gdpPercap_df

Creating the new data frame uk_gdpPercap_df

To look at the per capita GDP in a way that’s more meaningful, let’s create a new variable gdpPercap_rel, that is the gdpPercap of the country relative to the United Kindom gdpPercap of that same year.

We can do this by dividing gdpPercap by the United Kingdom’s gdpPercap, making sure that we always divide two numbers that are from the same year. To do this we need to first:

  1. Create a new dataframe uk_gdpPercap_df
  2. Filter the rows for country == "United Kingdom".
  3. Select the columns gdpPercap and year.
  4. Rename the variable gdpPercap, uk_gdpPercap.

We want to divide all the other gdpPercap by the UK gdpPercap in that same year.

One way we can do this is to match the two data frames using a left_join on the common variable, year. This will effectively make a new column, for the uk_gdpPercap that is joined up to our gapminder data frame.

A left_join keeps all of the rows from the first data frame (x = gapminder) and on the matching rows from the other data frame (y = uk_gdpPercap_df), using the values in the column year to do the matching (by = "year").

Now that we have the gdpPercap and uk_gdpPercap matched up, we can can calculate the relative GDP per capita gdpPercap_rel.

We can doublecheck that our calculation worked by filtering for the United Kingdom to check that the relative gdp per capita is 1.

How many countries had a smaller gdp per capita than the UK each year?

6.7.7 Answers to our poll

Using what we’ve learned so far, let’s go back to our original comparisons.

Which of the three pairs of countries do you think have a higher infant mortality rate in 2007? Which are the most similar?

  1. Sri Lanka or Turkey
  1. Poland or Malaysia
  1. Pakistan or Vietnam

Which of the two pairs of countries do you think have a higher life Expectancy in 2007? Which are the most similar?

  1. South Africa or Yemen
  1. Chile or Hungary

For the two pairs of countries below, which country do you think had the highest gdpPercap in 2007?

  1. Switzerland or Kuwait
  1. Colombia or Nepal

Which results did you find the most surprising?

7 Intro to Data Visualisation Using ggplot2

One of the most meaningful ways to interpret and make sense of data is through plotting! Plotting the data allows us to look for relationships between variables, generate hypotheses, and identified patterns. A great package to make attractive graphics is ggplot2.

Let’s start by making a scatter plot of life Expectancy by year for a handful of countries in the middle east.

First we can make a new dataframe called gapminder_middle_east

7.0.1 Creating a scatter plot using ggplot2

Then we can make a scatter plot in ggplot2 using the function geom_point plotting year on the x axis and lifeExp on the y axis.

7.1 ggplot structure

To make a plot with ggplot2 you begin a plot with the function ggplot():

  • ggplot()

The first argument of ggplot() is the dataset to use in the graph:

  • ggplot(data = gapminder_middle_east)

You complete your graph by adding one or more layers to ggplot().

  • e.g. geom_point().

The function geom_point() adds a layer of points to your plot. Each geom function in ggplot2 takes a mapping argument which defines how variables in your dataset are mapped to visual properties. The mapping argument is always paired with aes(). In the case of geom_point the x and y arguments of aes() specify which variables to map to the x and y axes.

  • geom_point(mapping = aes(x = year, y = lifeExp)).

When these are specified, ggplot2 looks for the mapped variables (year and lifeExp) in the data argument.

7.2 Graphing template

Graphs in ggplot take the following form

Depending on the <GEOM_FUNCTION> used the arguments may vary. For instance if we are plotting a histogram to look at the range of life Expectancy in the dataset, we only need to provide a variable for the x axis. We also need to provide a value for the argument bins().

Take a look at what different plots are available by typing geom_ and then tab.

7.2.1 Aesthetic mappings

You can add a third variable, like country, to a two dimensional scatterplot by mapping it to an aesthetic. Aesthetics are visual properties of the objects in your plot. Aesthetics include things like the size, the shape, or the color of your points. You can display a point (like the one below) in different ways by changing the values of its aesthetic properties.

It seems like overall, life expectancy (lifeExp) has been improving in most countries with time, but some are improving faster than others. We can add additional information to the aes argument to explore the data further. For instance, we can colour the points by country.

7.2.1.1 Colouring points by a factor

This makes the graph a little easier to read, but some of the colours blend together. We can add an additional argument to change the shape of the point as well.

7.2.1.3 Changing point size equal to a numeric variable

We can also change the size, making it equal to gdpPercap

In this case ggplot gives us two legends, one for the size of the points and one for the country colour. Most of the countries gdpPercap has been increasing overtime, although some increases are more slight than others.

We could also make the plot with the points sized by relative gdp per capita gdpPercap_rel

7.2.1.7 Make multiple plots using facet_wrap()

The function facet_wrap() wraps a series of plot panels into two dimensions. We can use it in our plot to make a plot panel for each country. There are other options for facet_wrap, take a look at the help file by typing ?facet_wrap to look at other examples like wrapping the data by two variables.

And to save the last plot we made, we can run the following lines of code.

7.2.1.8 Save a plot using ggsave()

From this plot it seems like the countries with the largest gdpPercap seem to overall have higher life Expectancy.

7.2.2 Making a time series plot

Time series plots are a great way to look at the evolution of a process through time. We can use a time series plot to ask the questions:

  1. How does GDP per capita change with time?

Overall all the South American country’s in the plot above GDP per capita have increased over time. But how does this compare to how the UK’s gdp per capita changed?

  1. Which country’s GDP per capita relative to the UK changed the most over time? Which changed the least? Which country’s relative GDP increased the most from start to finish?
  1. What’s the relationship between Infant Mortality and Time?
  1. What is the relationship between fertility and time?

What kind of trends can you pick out through time? Which country’s fertility dropped the fastest? Which country’s fertility changed the least? When do we start to have data for fertility from these countries?

7.2.3 Exercises:

  1. Run the following lines of code to make the plot below. Add the title “Life Expectancy in the Americas 1952 vs 2007” using ggtitle().
  1. The plot below shows the difference in life expectancy for the 10 countries with the largest difference.
  • Change the x = fct_reorder(country, life_exp_diff) to x = country. What does fct_reorder do? Take a look at ?fct_reorder for more info.

  • Rerun the plot, this time removing coord_flip(). What does the function coord_flip() change in the plot?

  1. Try recreating the following plot by filling in the blanks below

Bonus

  1. Change the plot so it shows the difference in life expectancy for the 10 countries with the smallest difference.

Hint: You’ll need to change top_n(), take a look at the help file using ?top_n and read what it says for the argument n.

  • Update the subtitle sub = to reflect that we’re looking at the countries with the smallest difference.
  1. What’s the relationship between Infant Mortality and Year by continent? Fill in the blanks to find out.

5a. Filter the data to find out which countries in Europe had a infant mortality rate greater than 60?

N.B. You do not need to make a plot.

  1. Run the code below and take a look at the plot of the relationship between life expectancy and year by continent. Use the tidyverse verbs to figure out which countries are represented by the dips in Africa (1990s) and Asia (1970s).

Which country is represented in the dip in Africa?

Which country is represented in the dip in Asia?

8 Getting Help

  1. Help and Vignette Check the function or the documentation of the package you’re working with using the help function ? or vignette respectively.
  1. CRAN Task View Looking for a package to carry out a particular analysis? Check out CRAN Task View

  2. Stack Overflow Stack Overflow Check out Stack Overflow. This is one of the first calls where members from the R Community will help you answer questions.

  3. Cheatsheets Many of the tidyverse packages come with their own cheatsheets, which are a quick reference on how to use various functions. It also gives a good overview of what functions are available.

  1. Google. Google is your friend! Type “R help” followed by the warning or error message you received and I guarantee there will be someone who has had this problem before.

  2. Meet ups and coding clubs Join a meet up or coffee and code group. Check out R-Ladies.

  3. Further resources Looking to develop your learning further? Check out my trello board on R Resources for Data Science. This is still a work in progress, but I’m continually updating it with useful resources.

9 References

9.1 Acknowledgements

Thank you to Jhai Ghaghada for laying the foundation for the Intro to R course. Thanks to Andrew Meechan, Rebecca Brown, David Bell, and Lewis Dunne for being the guinea pigs for this work. Special thanks to Rebecca Brown for the comments and feedback on the content.

LS0tDQp0aXRsZTogIkludHJvIHRvIFIgZm9yIERhdGEgU2NpZW5jZSINCmF1dGhvcjogIkRyLiBMYXVyaWUgQmFrZXIiDQpkYXRlOiAiMDMvMDIvMjAyMCINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUNCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogJzInDQogICAgdG9jX2Zsb2F0OiB5ZXMNCiAgaHRtbF9ub3RlYm9vazoNCiAgICBoaWdobGlnaHQ6IGhhZGRvY2sNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIHRoZW1lOiBzaW1wbGV4DQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDINCiAgICB0b2NfZmxvYXQ6IHllcw0KLS0tDQoNCiMgV2VsY29tZSB0byBSIQ0KDQpSIGlzIGEgdmVyc2F0aWxlIGNvZGluZyBsYW5ndWFnZSBmb3IgZGF0YSBzY2llbmNlLCB3aXRoIGEgd29uZGVyZnVsIGNvbW11bml0eSBzdXBwb3J0aW5nIGl0LiBIZXJlJ3MgYSBzaG9ydCBsaXN0IG9mIHNvbWUgb2YgdGhlIHRoaW5ncyB0aGF0IG1ha2UgUiBncmVhdC4NCg0KMS4gKipGcmVlIGFuZCBvcGVuIHNvdXJjZSoqIEl0J3MgYSBmcmVlIGFuZCBvcGVuIHNvdXJjZSBwcm9ncmFtbWluZyBsYW5ndWFnZSBhbmQgZW52aXJvbm1lbnQgZm9yIHN0YXRpc3RpY2FsIGNvbXB1dGluZywgbWFjaGluZSBsZWFybmluZywgYW5kIGdyYXBoaWNzLg0KDQoyLiAqKlJlcHJvZHVjaWJpbGl0eSBhbmQgUmVwb3J0aW5nKiogd3JpdGluZyByZXByb2R1Y2libGUgcmVwb3J0cyBpcyBub3cgZWFzaWVyIHRoYW4gZXZlciB0aGFua3MgdG8gcGFja2FnZXMgbGlrZSBrbml0ciBhbmQgUiBNYXJrZG93bi4gDQozLiAqKlJTdHVkaW8qKiBSU3R1ZGlvIGlzIGEgcG93ZXJmdWwgSW50ZXJhY3RpdmUgRGV2ZWxvcG1lbnQgRW52aXJvbm1lbnQgdGhhdCBoYXMgbWFkZSBsZWFybmluZyBSIGFuZCB1c2luZyBSIG11Y2ggZWFzaWVyLiBXaXRoIG9wdGlvbnMgZm9yIHdvcmtmbG93IGFuZCBwcm9qZWN0IG1hbmFnZW1lbnQuICANCjQuICoqR3JhcGhpY3MuKiogUiBjYW4gYmUgdXNlZCB0byBtYWtlIGdyZWF0IGRhdGEgZ3JhcGhpY3MsIHdpdGggcGFja2FnZXMgbGlrZSBnZ3Bsb3QyIGhlbHBpbmcgdXNlcnMgbWFrZSBncmFwaGljcyBpbiBhbiBpbnR1aXRpdmUgd2F5LiANCg0KNS4gKipSIFBhY2thZ2VzIGFuZCBDb21tdW5pdHkqKiBXaXRoIG92ZXIgMTUsMDAwIHBhY2thZ2VzIG9uIFtDUkFOXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy8pIGFsb25lLCB0aGVyZeKAmXMgcHJldHR5IG11Y2ggYSBwYWNrYWdlIHRvIGRvIGFueXRoaW5nLiBUaGUgZ3JlYXRlciBSIGNvbW11bml0eSBoYXMgYWxzbyBleHBhbmRlZCB0cmVtZW5kb3VzbHkgb3ZlciB0aW1lLCBicmluZ2luZyBpbiBuZXcgdXNlcnMgYW5kIHB1c2hpbmcgUiB0byBiZSB1c2VmdWwgaW4gbW9yZSBhcHBsaWNhdGlvbnMuIEVhY2ggeWVhciB0aGVyZSBhcmUgdGhvdXNhbmRzIG9mIG1lZXR1cHMsIGNvbmZlcmVuY2VzLCBzZW1pbmFycywgYW5kIHdvcmtzaG9wcyBvbiBSIGFsbCBhcm91bmQgdGhlIHdvcmxkLg0KDQoNCiMgT2JqZWN0aXZlczoNCg0KIVtdKHBpY3R1cmVzL0xpZmVfRXhwZWN0YW5jeV9ieV9ZZWFyMi5wbmcpe3dpZHRoPTY1MHB4fQ0KDQoNCi0gRmFtaWxpYXJpc2UgeW91cnNlbGYgd2l0aCBSU3R1ZGlvIGFuZCBSIE5vdGVib29rcywgd2hpY2ggaXMgd2hhdCB3ZeKAmWxsIHVzZSB0byBpbnRlcmFjdCB3aXRoIFIuDQoNCi0gTGVhcm4gYWJvdXQgdGhlIHNpbXBsZSBkYXRhIHN0cnVjdHVyZXMgaW4gUjogb2JqZWN0LCB2ZWN0b3IsIGFuZCBkYXRhIGZyYW1lLg0KDQotIEV4cGxvcmUgUidzIGJhc2ljIGRhdGEgdHlwZXMgPSBpbnRlZ2VyLCBjaGFyYWN0ZXIsIG51bWVyaWMsIGV0Yy4gDQoNCi0gTGVhcm4gdG8gcmVhZCBkYXRhIGludG8gUi4gDQoNCi0gSW50cm9kdWN0aW9uIHRvIGRhdGEgd3JhbmdsaW5nIHVzaW5nIHRoZSBgdGlkeXZlcnNlYCBzZXQgb2YgbWV0YXBhY2thZ2VzLiANCg0KLSBVc2UgdGhlIHRpZHl2ZXJzZSB2ZXJicyB0byBleHBsb3JlIHRoZSBbZ2FwbWluZGVyXShodHRwczovL3d3dy5nYXBtaW5kZXIub3JnL2RhdGEvKSBkYXRhIHNldCB3aGljaCBpbmNsdWRlcyBzdGF0aXN0aWNzIGZvciBjb3VudHJpZXMgYXJvdW5kIHRoZSB3b3JsZCBpbmNsdWRpbmcgbGlmZSBleHBlY3RhbmN5LCBwb3B1bGF0aW9uLCBhbmQgR0RQIHBlciBjYXBpdGEuDQoNCi0gTGVhcm4gdG8gbWVyZ2UgZGF0YXNldHMgdXNpbmcgYGxlZnRfam9pbmAuDQoNCi0gQ3JlYXRlIG1lYW5pbmdmdWwgdmlzdWFsaXNhdGlvbnMgb2YgdGhlIGRhdGEgdXNpbmcgYGdncGxvdDJgLg0KDQotIExlYXJuIHdoZXJlIHRvIGdvIGZvciBoZWxwLiANCg0KDQojIFJTdHVkaW8gYW5kIFJOb3RlYm9va3MNCg0KRmlyc3QgbGV0J3Mgc2V0IGl0IHNvIHRoYXQgb3VyIG5vdGVib29rIHNob3dzIHVwIGluIG91ciB2aWV3ZXIuIA0KDQoqIENsaWNrIG9uIHRoZSBnZWFyIGljb24gbmV4dCB0byBLbml0IG9uIHRoZSBtZW51LiBTZWxlY3QgUHJldmlldyBpbiBWaWV3ZXIgUGFuZS4gDQoNCiFbXShwaWN0dXJlcy9SX25vdGVib29rX3ZpZXdpbmcucG5nKXt3aWR0aD02NTBweH0NCg0KKiBOb3cgY2xpY2sgb24gdGhlIGxpdHRsZSBhcnJvdyBuZXh0IHRvIEtuaXQgYW5kIHNlbGVjdCAiS25pdCB0byBIVE1MIi4NCg0KIyMgUlN0dWRpbw0KDQpJbiB0aGlzIHRyYWluaW5nIHdlIHdpbGwgYmUgdXNpbmcgUlN0dWRpby4gUlN0dWRpbyBpcyBhbiBpbnRlcmFjdGl2ZSBkZXZlbG9wbWVudCBlbnZpcm9ubWVudCAoSURFKSBmb3IgUiBhbmQgaXMgYnJva2VuIGRvd24gaW50byB2YXJpb3VzIHBhbmVscyBmb3Igb3VyIGNvbnZlbmllbmNlLiANCg0KIVtTb3VyY2U6IFtSLUxhZGllcyBTeWRuZXkgQmFzaWMgQmFzaWNzLl0oaHR0cHM6Ly9ybGFkaWVzc3lkbmV5Lm9yZy9jb3Vyc2VzL3J5b3V3aXRobWUvMDEtYmFzaWNiYXNpY3MtMS8pIF0ocGljdHVyZXMvUlN0dWRpb19xdWFkcmFudHMuanBnKXt3aWR0aD02NTBweH0NCg0KLSAqKlExKio6IHNjcmlwdCwgZGF0YSwgY29tbWFuZCB0byBydW4gc2NyaXB0DQogIC0gVGhpcyBpcyB0aGUgcGFuZWwgeW914oCZcmUgcmVhZGluZyB0aGlzIHR1dG9yaWFsIGluLiBJdCBjb250YWlucyB0aGUgc2NyaXB0IGVkaXRvciB3aGVyZSB3ZSBjYW4gY3JlYXRlIGFuZCBlZGl0IFIgTm90ZWJvb2sgZmlsZXMsIGFtb25nIG90aGVyIGZpbGVzLg0KLSAqKlEyKio6IGNvbnNvbGUNCiAgLSBUaGlzIGlzIHRoZSBDb25zb2xlIFBhbmVsIHdoZXJlIFIgY29kZSBpcyBwYXNzZWQgdG8gYW5kIGV4ZWN1dGVkLg0KLSAqKlEzKio6IGVudmlyb25tZW50DQogIC0gVGhlIGVudmlyb25tZW50IHRhYiBrZWVwcyB0cmFjayBvZiB2YXJpYWJsZXMgd2XigJl2ZSBjcmVhdGVkIGluIHRoaXMgd29ya3NwYWNlLg0KLSAqKlE0Kio6IGZpbGVzLCBwbG90cywgcGFja2FnZXMsIGhlbHANCiAgLSBUaGlzIGlzIGEgbXVsdGktcHVycG9zZSBwYW5lbCB3aGljaCBjb250YWluczoNCiAgICAgIC0gKipGaWxlczoqKiBBIGJhc2ljIGZpbGUgZXhwbG9yZXIsDQogICAgICAtICoqUGxvdHM6KiogV2hlcmUgcGxvdHMgY2FuIGJlIHJlbmRlcmVkLA0KICAgICAgLSAqKlBhY2thZ2VzOioqIGluc3RhbGwgYW5kIGltcG9ydCBsaWJyYXJpZXMgaW50byBSLA0KICAgICAgLSAqKkhlbHA6KiogRXhwbG9yZXIgZm9yIERvY3VtZW50YXRpb24gb2YgZnVuY3Rpb25zIGFuZCBsaWJyYXJpZXMsDQogICAgICAtICoqVmlld2VyOioqIFZpZXcgbG9jYWwgd2ViIGNvbnRlbnQgZS5nLiBTaGlueSBhcHAuDQoNCg0KIyMjIFNldHRpbmdzDQoNClNvbWUgcGVvcGxlIGxpa2UgUlN0dWRpbyB0byByZW1lbWJlciBzdHVmZiBmcm9tIHNlc3Npb24gdG8gc2Vzc2lvbi4gSG93ZXZlciwgdGhpcyBjYW4gYmUgZGFuZ2Vyb3VzIGFzIHByZXZpb3VzIHdvcmsgYW5kIHBhY2thZ2VzIGNhbiBpbnRlcmZlcmUgd2l0aCBjdXJyZW50IGNvZGUgYW5kIG1ha2UgeW91ciBjb2RlIG1vcmUgYnJlYWthYmxlLiBUbyBhdm9pZCB0aGlzLCBpdCBpcyByZWNvbW1lbmRlZCB0aGF0IHlvdSBjaGFuZ2UgdHdvIHNldHRpbmdzIGluIFJTdHVkaW8uDQoNCiFbU291cmNlOiBbUi1MYWRpZXMgU3lkbmV5IEJhc2ljIEJhc2ljcy5dKGh0dHBzOi8vcmxhZGllc3N5ZG5leS5vcmcvY291cnNlcy9yeW91d2l0aG1lLzAxLWJhc2ljYmFzaWNzLTEvKSBdKHBpY3R1cmVzL1JTdHVkaW9fc2V0dGluZ3MuanBnKXt3aWR0aD02NTBweH0NCg0KTG9jYXRlIFByZWZlcmVuY2VzIChPbiBXaW5kb3dzLCB0aGlzIGlzIGluIHRoZSBUb29scy0+R2xvYmFsIE9wdGlvbnMgbWVudTsgb24gYSBNYWMsIHRoaXMgaXMgaW4gdGhlIFJTdHVkaW8gbWVudSkuIEluIHRoZSBHZW5lcmFsIHRhYiwgdW5jaGVjayDigJxSZXN0b3JlIC5SRGF0YeKApuKAnSBhbmQgc2VsZWN0IOKAnG5ldmVy4oCdIGZvciDigJxTYXZlIHdvcmtzcGFjZeKApuKAnQ0KDQojIyBSIE5vdGVib29rcw0KDQpSIE5vdGVib29rcyBnaXZlIHRoZSBvcHBvcnR1bml0eSB0byBjb21iaW5lIGNvZGUgYW5kIGRlc2NyaXB0aW9uIGluIGEgc2luZ2xlIGh1bWFuLXJlYWRhYmxlIG5vdGVib29rLiBZb3UgY2FuIGNvbmR1Y3QgYW5hbHlzaXMgYW5kIGdpdmUgaW50ZXJwcmV0YXRpb24gc2lkZS1ieS1zaWRlISBUaGlzIG1lYW5zIHRoYXQgeW91ciBlbnRpcmUgYW5hbHl0aWNhbCBhcHByb2FjaCBjYW4gYmUgZG9jdW1lbnRlZCB0b2dldGhlciwgZnJvbSB0aGUgcmF3IGRhdGEgdG8gdGhlIGFuYWx5c2lzIGFuZCBmaW5hbGx5IHJlc3VsdHMgYW5kIGNvbmNsdXNpb25zLg0KDQojIyMgV2hlcmUgdGhlIGNvZGUgZ29lcy4uLg0KDQpXZSB3aWxsIGJlIGVudGVyaW5nIHRoZSBSIGNvZGUgaW50byB0aGVzZSBibG9ja3M6DQoNCmBgYHtyIFByaW50IGEgc3RhdGVtZW50fQ0KDQpwcmludCgnY29kZSBnb2VzIGhlcmUhJykNCg0KYGBgDQoNCldlIGNhbiBydW4gdGhlIGJsb2NrIG9mIGNvZGUgdXNpbmcgdGhlIHBsYXkgYnV0dG9uIG9uIHRoZSByaWdodC4gV2UgY2FuIGFsc28gcnVuIHRoaXMgYmxvY2sgb2YgY29kZSB3aXRoIGFsbCBwcmV2aW91cyBibG9ja3Mgb2YgY29kZSB3aXRoIHRoZSBkb3dud2FyZHMgZmFjaW5nIHBsYXkgYnV0dG9uIGluIHRoZSBtaWRkbGUuIA0KDQpJbiBzb21lIHBsYWNlcyBJIGhhdmUgYWRkZWQgYWRkaXRpb25hbCBhcmd1bWVudHMgdG8gdGhlIGNvZGUgY2h1bmsgKGUuZy4gYGV2YWwgPSBGQUxTRWApIHNvIHRoYXQgc29tZXRoaW5nIGlzIG5vdCBldmFsdWF0ZWQgaW4gb3JkZXIgZm9yIHRoZSBodG1sIGZpbGUgdG8gY29tcGlsZS4gU2VlIHRoZSBleGFtcGxlIGJlbG93Og0KDQpgYGB7ciBPcHRpb25zIGZvciBSIGNodW5rcywgZXZhbCA9IEZBTFNFfQ0KDQpwcmludCgnY29kZSBnb2VzIGhlcmUhJykNCg0KYGBgDQoNCkZlZWwgZnJlZSB0byBjaGFuZ2UgdGhpcyBieSBzaW1wbHkgcmVtb3ZpbmcgdGhlIGAsIGV2YWwgPSBGQUxTRWAgZXNwZWNpYWxseSBhcyB5b3UgdXBkYXRlIHRoZSBkb2N1bWVudC4gSG93ZXZlciwgbm90ZSB0aGF0IGlmIHRoZXJlIGFyZSBhbnkgY29kZSBlcnJvcnMgbGVmdCwgdGhlIGh0bWwgZmlsZSB3aWxsIG5vdCBjb21waWxlLiAgDQoNCiMjIyBBZGRpbmcgY29tbWVudHMgYW5kIG90aGVyIGhlbHBmdWwgc2hvcnRjdXRzDQoNCiogWW91IGNhbiBhZGQgY29tbWVudHMgd2l0aGluIHlvdXIgUiBjb2RlIGNodW5rIHVzaW5nIGAjYC4gDQoNCiAgICAqIFlvdXIgY29tbWVudHMgY2FuIGJlIG5vdGVzIGZvciB5b3Vyc2VsZiwgb3IgZXhwbGFuYXRpb24gb2Ygd2hhdCB0aGUgY29kZSBpcyBkb2luZyBmb3Igc29tZW9uZSB0byBmb2xsb3cuIA0KICAgICogWW91IGNhbiBhbHNvIGNvbW1lbnQgb3V0IGNvZGUgeW91IGRvbid0IHdhbnQgdG8gYmUgaW1tZWRpYXRlbHkgcnVuLiANCg0KKiBZb3UgY2FuIGNvbW1lbnQgb3IgdW5jb21tZW50IGNvZGUgdXNpbmcgYEN0cmwgKyBTaGlmdCArIENgLiANCg0KKiBZb3UgY2FuIHJ1biBhIGxpbmUgb2YgY29kZSBieSBwbGFjaW5nIHlvdXIgY3Vyc29yIGFueXdoZXJlIG9uIHRoZSBsaW5lIGFuZCB1c2luZyBgQ3RybCArIEVudGVyYC4gVGhpcyB3aWxsIGV4ZWN1dGUgdGhlIGxpbmUgb2YgY29kZSBhbmQgbW92ZSB0aGUgY3Vyc29yIHRvIHRoZSBuZXh0IGxpbmUuDQoNCg0KIyBCYXNpY3MNCg0KIyMgT2JqZWN0cw0KDQpMZXQncyBzdGFydCBieSBtYWtpbmcgYW4gYXNzaWdubWVudCBhbmQgaW5zcGVjdGluZyB0aGUgb2JqZWN0IHdlIGNyZWF0ZWQuDQoNCmBgYHtyIEZpcnN0IFIgT2JqZWN0fQ0KDQp4IDwtIDEwKjUNCg0KeA0KDQpgYGANCg0KQWxsIFIgc3RhdGVtZW50cyB3aGVyZSB5b3UgY3JlYXRlIG9iamVjdHMgYnkgbWFraW5nIGFuICdhc3NpZ25tZW50JywgdGFrZSB0aGUgZm9ybToNCg0KIC0gIGBvYmplY3RfbmFtZSA8LSB2YWx1ZWANCg0KWW91IGNhbiB0aGluayBvZiBvYmplY3RzIGFzIHN0b3JhZ2UgY29udGFpbmVycyBmb3IgdmFsdWVzLiBBbiBvYmplY3QgaXMgY3JlYXRlZCB1c2luZyB0aGUgb3BlcmF0b3IgYDwtYC4gSXQgY2FuIGJlIGEgcGFpbiB0byB0eXBlIGA8LWAsIGJ1dCBkb24ndCBiZSB0ZW1wdGVkIHRvIHVzZSBgPWAgYXMgdGhpcyBoYXMgYW5vdGhlciBzcGVjaWZpYyB1c2UgaW4gdGhlIFIgbGFuZ3VhZ2UuIA0KDQojIyMgKipOYW1pbmcgb2JqZWN0cyoqDQoNCllvdSBjYW4gbmFtZSB5b3VyIG9iamVjdHMgYW55dGhpbmcuIFlvdSBjYW4gdXNlIGxldHRlcnMsIG51bWJlcnMsIHBlcmlvZHMgYW5kIHVuZGVyc2NvcmVzLiBZb3UganVzdCBjYW4ndCBzdGFydCBuYW1lcyB3aXRoIGEgZG90IG9yIGEgbnVtYmVyIGAxLDIsMy4uLmAgYW5kIHlvdXIgbmFtZSBjYW5ub3QgY29udGFpbiBvdGhlciBjaGFyYWN0ZXJzIHN1Y2ggYXMgYSBjb21tYSBvciBhIHNwYWNlLiANCg0KDQpgYGB7ciBOYW1lcyB0aGF0IHdvcmsgZm9yIG9iamVjdHN9DQoNCnRoaXNfd29ya3MgPC0gMTAqNQ0KDQp0aGlzX3dvcmtzDQoNCmBgYA0KDQpUcnkgcnVubmluZyB0aGUgZm9sbG93aW5nIGxpbmVzIG9mIGNvZGUuIFRyeSB1bmNvbW1lbnRpbmcgdGhlIGNvZGUgYCMgdGhpc19kb2Vzbid0X3dvcmsgPC0gMTAqNWAgYnkgY2xpY2tpbmcgb24gdGhlIGxpbmUgYW5kIHVzaW5nIGBDdHJsICsgU2hpZnQgKyBDYC4NCg0KYGBge3IgTmFtZXMgdGhhdCBkbyBub3Qgd29yayBmb3Igb2JqZWN0cywgZXZhbCA9IEZBTFNFfQ0KDQojIHRoaXNfZG9lc24ndF93b3JrIDwtIDEwKjUNCg0KYGBgDQoNCiMjIyBNYWtlIHlvdXIgb2JqZWN0IG5hbWVzIGVhc3kgdG8gcmVhZA0KDQpJdCBpcyB1c2VmdWwgZm9yICoqZnV0dXJlIHlvdSoqIGFuZCB5b3VyIGNvbGxhYm9yYXRvcnMgdG8gbmFtZSB5b3VyIG9iamVjdHMgc29tZXRoaW5nIHRoYXQgaXMgcmVhc29uYWJsZSBhbmQgZGVzY3JpYmVzIHdoYXQgdGhlIG9iamVjdCBjb250YWlucy4gVG8gbWFrZSB5b3VyIG9iamVjdCBuYW1lcyBlYXN5IHRvIHJlYWQgaXQgaXMgdXNlZnVsIHRvIGFkb3B0IGEgY29udmVudGlvbiBmb3IgZGVtYXJjYXRpbmcgd29yZHMgaW4gbmFtZXMuDQoNCmBgYHtyIE5hbWluZyBDb252ZW50aW9ucywgZXZhbCA9IEZ9DQoNCmplbm55X2JyeWFuX2FuZF9oYWRsZXlfd2lja2hhbV91c2Vfc25ha2VfY2FzZSANCg0Kc29tZS5wZW9wbGUudXNlLnBlcmlvZHMNCg0Kb3RoZXJzVXNlQ2FtZWxDYXNlDQoNCmBgYA0KDQojIyMgVXNpbmcgVGFiIENvbXBsZXRpb24gdG8gQ29tcGxldGUgT2JqZWN0IE5hbWVzDQoNCk1ha2UgYSBuZXcgb2JqZWN0IA0KDQpgYGB7ciBNYWtlIGEgbmV3IG9iamVjdCB3aXRoIGEgbG9uZyBuYW1lfQ0KDQphX3ZlcnlfbG9uZ19uYW1lIDwtIDdeMiANCg0KYGBgDQoNClNvbWV0aW1lcyB0byBtYWtlIG91ciBvYmplY3QgbmFtZXMgcmVhZGFibGUgd2UgdXNlIGxvbmcgbmFtZXMgdGhhdCBjYW4gYmUgbGFib3VyaW91cyB0byB0eXBlLiBMdWNraWx5LCBSU3R1ZGlvIGhhcyBhIGhhbmR5IGNvbXBsZXRpb24gZmFjaWxpdHkuIA0KDQpTdGFydCBieSB0eXBpbmcgdGhlIGZpcnN0IGZldyBsZXR0ZXJzIG9mIGBhX3ZlcnkuLi5gIGluIHRoZSBjb2RlIGNodW5rIGJlbG93IGFuZCB0eXBlIGBUQUJgIHRvIGNvbXBsZXRlIHRoZSBuYW1lLiANCg0KYGBge3IgVXNpbmcgVGFiIHRvIFRlc3Qgb3V0IHRoZSBDb21wbGV0aW9uIEZhY2lsaXR5IGluIFJTdHVkaW99DQoNCmFfdmVyeV9sb25nX25hbWUNCg0KYGBgDQoNCg0KIyMjIFIgaXMgY2FzZS1zZW5zaXRpdmUgYW5kIGRvZXNuJ3QgbGlrZSB0eXBvcw0KDQpMZXQncyB0cnkgaW5zcGVjdGluZyB0aGUgb2JqZWN0IGFnYWluLg0KDQpgYGB7ciBSIGlzIGNhc2Utc2Vuc2l0aXZlIGFuZCBkb2VzIG5vdCBsaWtlIHR5cG9zLCBldmFsID0gRkFMU0V9DQojIFdoYXQgaGFwcGVucyBpZiB5b3UgcnVuOg0KDQphX3ZyeV9sb25nX25hbWUNCg0KQV92ZXJ5X2xvbmdfbmFtZQ0KDQpgYGANCg0KUiBpcyB2ZXJ5IHNlbnNpdGl2ZSB0byBib3RoIGNhc2UgYW5kIHNwZWxsaW5nIG1pc3Rha2VzIGFuZCB3b24ndCBydW4gdW5sZXNzIHRoaW5ncyBhcmUgc3BlbGxlZCBjb3JyZWN0bHkgYW5kIGFyZSBpbiB0aGUgcmlnaHQgY2FzZS4gSWYgeW91IGdldCBhbiBlcnJvciwgY2hlY2sgeW91ciBzcGVsbGluZyEgTW9yZSB0aGFuIDgwJSBvZiB0aGUgdGltZSwgdGhpcyBpcyBsaWtlbHkgdGhlIGNhdXNlIG9mIHlvdXIgZXJyb3IhIA0KDQojIyBWZWN0b3JzDQoNCkEgYHZlY3RvcmAgaXMgYSAxLWRpbWVuc2lvbmFsIG9yZGVyZWQgY29sbGVjdGlvbiBvZiBlbGVtZW50cywgKiphbGwgb2YgdGhlIHNhbWUgdHlwZS4qKiBJdCBpcyB0aGUgZnVuZGFtZW50YWwgZGF0YSBzdHJ1Y3R1cmUgaW4gUiB3aXRoIGEgbG90IG9mIHVzZWZ1bCBwcm9wZXJ0aWVzLiANCg0KV2UgY2FuIGV4dHJhY3QgYW4gZWxlbWVudCBmcm9tIGEgdmVjdG9yIGJ5IHJlZmVyZW5jaW5nIGl0cyBwb3NpdGlvbi4gTGV0J3MgbWFrZSBhIG5ldyB2ZWN0b3IgY2FsbGVkIGBjaGFyYWN0ZXJfdmVjdG9yYCB1c2luZyB0aGUgZnVuY3Rpb24gYGMoKWAgd2hpY2ggY2FuIGJlIHVzZWQgdG8gKipjKCkqKm9tYmluZSBlbGVtZW50cy4gIA0KDQojIyMgQ3JlYXRpbmcgYSB2ZWN0b3Igd2l0aCBgYygpYA0KDQpgYGB7ciBEZWZpbmUgYSBjaGFyYWN0ZXIgdmVjdG9yfQ0KDQojIyBEZWZpbmluZyB0aGUgY2hhcmFjdGVyIHZlY3RvcjoNCg0KY2hhcmFjdGVyX3ZlY3RvciA8LSBjKCJFVCIsICJQaG9uZSIsICJIb21lIiwgIkVUIiwgIlBob25lIiwgIkhvbWUiKQ0KDQpgYGANCg0KTm90aWNlIHRoYXQgd2hlbiB3ZSBzcGVjaWZ5IHdvcmRzIG9yIGNoYXJhY3RlcnMsIHdlIHVzZSBgIiJgLg0KDQojIyMgQ2hlY2sgdGhlIHN0cnVjdHVyZSBvZiB0aGUgdmVjdG9yIHVzaW5nIGBzdHIoKWANCg0KYGBge3IgQ2hlY2tpbmcgdGhlIHN0cnVjdHVyZSBvZiB0aGUgY2hhcmFjdGVyIHZlY3Rvcn0NCg0Kc3RyKGNoYXJhY3Rlcl92ZWN0b3IpDQoNCmBgYA0KDQpSIGlzIGFibGUgdG8gcmVjb2duaXNlLCB0aGFua3MgdG8gdGhlICIiIGFyb3VuZCBvdXIgdGV4dCB0aGF0IHRoZSB2ZWN0b3IgY29udGFpbnMgYSBjaGFyYWN0ZXIgc3RyaW5nIGBjaHJgLg0KDQojIyMgQ2hlY2sgdGhlIGxlbmd0aCBvZiBhIHZlY3RvciB1c2luZyBgbGVuZ3RoKClgDQoNCmBgYHtyIENoZWNraW5nIHRoZSBsZW5ndGggb2YgdGhlIGNoYXJhY3RlciB2ZWN0b3J9DQoNCmxlbmd0aChjaGFyYWN0ZXJfdmVjdG9yKQ0KDQpgYGANCg0KIyMjIEV4dHJhY3QgbXVsdGlwbGUgY29uc2VjdXRpdmUgZWxlbWVudHMgdXNpbmcgYDpgLiANCg0KYGBge3IgVGFrZSB0aGUgM3JkIGFuZCA0dGggYW5kIDV0aCBlbGVtZW50c30NCg0KY2hhcmFjdGVyX3ZlY3RvclszOjVdDQoNCmBgYA0KDQojIyMgUmVwbGFjZSBlbGVtZW50cyB1c2luZyBgPC1gDQoNClRyeSByZXBsYWNpbmcgdGhlIDR0aCBlbGVtZW50IHdpdGggeW91ciBuYW1lOg0KDQpgYGB7ciBSZXBsYWNlIGFuIGVsZW1lbnR9DQoNCmNoYXJhY3Rlcl92ZWN0b3JbNF0gPC0gIkxhdXJpZSINCg0KY2hhcmFjdGVyX3ZlY3Rvcg0KYGBgDQoNCiMjIyBEZWZpbmUgYSBudW1lcmljIHZlY3Rvcg0KDQpUaGUgc2FtZSBtZXRob2QgdXNlZCB0byBleHRyYWN0IGluZm9ybWF0aW9uIHdvcmtzIGZvciBhbnkgdHlwZSBvZiB2ZWN0b3IuIEhlcmUgd2UgY2FuIGRlZmluZSBhIG5ldyB2ZWN0b3IgYG51bWVyaWNfdmVjdG9yYCBjb250YWluaW5nIHRoZSBudW1iZXJzIDEsIDIsIDMsIDQsIGFuZCA1LiANCg0KYGBge3IgRGVmaW5lIGEgbnVtZXJpYyB2ZWN0b3J9DQoNCm51bWVyaWNfdmVjdG9yIDwtIGMoMTo1KSAjIGMoKSBpcyBhIGZ1bmN0aW9uIHRvDQoNCmBgYA0KDQojIyMgQ2hlY2sgdGhlIHN0cnVjdHVyZSB1c2luZyBgc3RyKClgDQoNCmBgYHtyIENoZWNrIHRoZSBzdHJ1Y3R1cmUgb2YgYSBudW1lcmljIHZlY3Rvcn0NCg0Kc3RyKG51bWVyaWNfdmVjdG9yKQ0KDQpgYGANCg0KQmVjYXVzZSB3ZSBoYXZlIHNwZWNpZmllZCB3aG9sZSBudW1iZXJzLCBSIGNhbiBlaXRoZXIgY2xhc3NpZnkgdGhlIHZlY3RvciBhcyBhbmQgaW50ZWdlciBgaW50YCBvciBhcyBudW1lcmljIGBudW1gLg0KDQojIyMgRXh0cmFjdCB0aGUgZmlyc3QgdHdvIGVsZW1lbnRzDQoNCmBgYHtyIFRha2UgdGhlIGZpcnN0IHR3byBlbGVtZW50cyBmcm9tIGEgbnVtZXJpYyB2ZWN0b3J9DQoNCm51bWVyaWNfdmVjdG9yWzE6Ml0NCg0KYGBgDQoNCiMjIyBFeHRyYWN0IG5vbi1jb25zZWN1dGl2ZSBlbGVtZW50cyB1c2luZyBgYygpYA0KDQpUcnlpbmcgdW5jb21tZW50aW5nIGFuZCBydW5uaW5nIHRoZSBsaW5lIGJlbG93Og0KDQpgYGB7ciBXZSBhbHdheXMgbmVlZCB0byB1c2UgYygpIHRvIHNwZWNpZnkgbXVsdGlwbGUgbm9uLWNvbnNlY3V0aXZlIHBvc2l0aW9uc30NCg0KIyBudW1lcmljX3ZlY3RvclsxLDNdDQoNCmBgYA0KDQpOb3RlIHRoYXQgd2UgY2FuIG9ubHkgc2VsZWN0IHRoZSAxIGFuZCAzIG9yIDEsIDMsIGFuZCA0IGVsZW1lbnRzIHVzaW5nIGBjKClgLiANCg0KYGBge3IgVXNlIGMoKSB0byBzcGVjaWZ5IG5vbi1jb25zZWN1dGl2ZSBwb3NpdGlvbnN9DQoNCm51bWVyaWNfdmVjdG9yW2MoMSwzOjQpXQ0KDQpgYGANCg0KIyMjIENoYW5naW5nIHRoZSBzdHJ1Y3R1cmUgb2YgYSB2ZWN0b3INCg0KTGV0J3MgbWFrZSBhIHNlY29uZCBudW1lcmljIHZlY3Rvci4gDQoNCmBgYHtyIE1ha2UgYSBzZWNvbmQgbnVtZXJpYyB2ZWN0b3J9DQoNCm51bWVyaWNfdmVjdG9yMiA8LSBjKDEuMSwzOjQpDQoNCiMjIENoZWNrIHRoZSBzdHJ1Y3R1cmUNCg0Kc3RyKG51bWVyaWNfdmVjdG9yMikNCg0KYGBgDQoNCiogWW91J2xsIG5vdGljZSB0aGF0IG5vdyB3aGVuIHdlIGNoZWNrIHRoZSBzdHJ1Y3R1cmUsIHRoZSB2ZWN0b3IgaXMgbnVtZXJpYyAobnVtKS4gVGhpcyBpcyBiZWNhdXNlIHdlIG5vdyBoYXZlIGEgbnVtYmVyIHdpdGggYSBkZWNpbWFsIHBsYWNlLiANCg0KKiBSIGlzIHdoYXQgaXMga25vd24gaW4gY29tcHV0ZXIgc2NpZW5jZSBhcyBhIGR5bmFtaWNhbGx5IHR5cGVkIGxhbmd1YWdlLiBSIGRvZXNuJ3QgcmVxdWlyZSB5b3UgdG8gc2V0IHRoZSBkYXRhIHR5cGUgd2hlbiB5b3UgY3JlYXRlIGEgdmVjdG9yLCBpbnN0ZWFkIGl0IGZpZ3VyZXMgb3V0IHdoYXQgdGhlIGJlc3QgZGF0YSB0eXBlIGlzIGZvciB0aGUgb2JqZWN0IHlvdSBhcmUgY3JlYXRpbmcgLSBudW1lcmljLCBjaGFyYWN0ZXIsIGZhY3RvciwgbG9naWNhbCwgZXRjLiANCg0KKiBIb3dldmVyLCBzb21ldGltZXMgdGhlIGRhdGEgdHlwZSB5b3Ugd2FudCB0byB3b3JrIHdpdGgsIGFuZCB0aGUgb25lIFIgaW5mZXJzIGFyZSBub3QgdGhlIHNhbWUuIFlvdSBjYW4gY2hhbmdlIHRoZSBkYXRhIHR5cGUgdXNpbmcgYSByYW5nZSBvZiBpbi1idWlsdCBmdW5jdGlvbnMgdGhhdCBlbmFibGUgeW91IHRvIGNvbnZlcnQgZGF0YSBmcm9tIG9uZSB0eXBlIHRvIGFub3RoZXIuIA0KDQojIyMjIFRoZSBgYXMuYCBmdW5jdGlvbnMNCg0KQSB1c2VmdWwgc2V0IG9mIGZ1bmN0aW9ucyBhcmUgdGhlIGBhcy5gIGZ1bmN0aW9ucywgd2hpY2ggdGFrZSB0aGUgZm9ybSBgYXMuPHN0cnVjdHVyZT5gLiBXZSBjYW4gdXNlIHRoaXMgdG8gc3BlY2lmeSB0aGUgc3RydWN0dXJlIG9mIG91ciBudW1lcmljIHZlY3RvciB0byBiZSBgbnVtZXJpY2AuIA0KDQpgYGB7ciBDaGFuZ2UgdGhlIHN0cnVjdHVyZSBvZiBhIG51bWVyaWMgdmVjdG9yIHVzaW5nIGFzLiBmdW5jdGlvbnN9DQoNCm51bWVyaWNfdmVjdG9yIDwtIGFzLm51bWVyaWMobnVtZXJpY192ZWN0b3IpDQoNCnN0cihudW1lcmljX3ZlY3RvcikNCg0KYGBgDQoNClRoZSBzdHJ1Y3R1cmUgb2YgdmVjdG9ycyBiZWNvbWVzIGltcG9ydGFudCB3aGVuIHdlIHVzZSBpdCB0byBhbmFseXNlIGRpZmZlcmVudCB0aGluZ3MuIA0KDQpgYGB7ciBDaGFuZ2UgdGhlIHN0cnVjdHVyZSBvZiBhIGNoYXJhY3RlciB2ZWN0b3IgdXNpbmcgYXMuIGZ1bmN0aW9uc30NCg0KY2hhcmFjdGVyX3ZlY3RvciA8LSBhcy5mYWN0b3IoY2hhcmFjdGVyX3ZlY3RvcikNCg0Kc3RyKGNoYXJhY3Rlcl92ZWN0b3IpDQoNCg0KYGBgDQoNCiogTm90ZSB0aGF0IG5vdyBgY2hhcmFjdGVyX3ZlY3RvcmAgaXMgbm93IGNsYXNzZWQgYXMgYSBmYWN0b3IgYEZhY3RvcmAgd2l0aCA0IGxldmVsczogIkVUIiwgIkhvbWUiLCAiTGF1cmllIiwgYW5kICJQaG9uZSIuDQoNCiogV2hlbiB5b3UgY3JlYXRlIGEgZmFjdG9yIGl0IHVzZXMgYW4gaW50ZWdlciBjb2RlIHRvIHJlcHJlc2VudCBlYWNoIGxldmVsLiBTbyB0aGF0ICJFVCIgaXMgYm90aCAiRVQiIGFuZCAxLCAiSG9tZSIgaXMgYm90aCAiSG9tZSIgYW5kIDIuIFlvdSdsbCBub3RpY2UgdGhhdCBpdCBhdXRvbWF0aWNhbGx5IHRha2VzIHRoZSBhbHBoYWJldGljIG9yZGVyIHdoZW4gZGV0ZXJtaW5pbmcgdGhlIGZhY3RvciBsZXZlbHMuIFRoaXMgbWVhbnMgdGhhdCBldmVuIHRob3VnaCAiUGhvbmUiIG9jY3VycyAybmQgaW4gb3VyIGNoYXJhY3RlciB2ZWN0b3IsIGl0IGdldHMgdGhlIGludGVnZXIgY29kZTogNC4gVGhpcyBpcyBqdXN0IGEgZGV0YWlsIG5vdywgYnV0IGJlY29tZXMgaW1wb3J0YW50IGluIHBsb3R0aW5nLCBlc3BlY2lhbGx5IGlmIHlvdSB3YW50IHRvIGNoYW5nZSB0aGUgb3JkZXIgaW4gd2hpY2ggeW91ciBmYWN0b3JzIGFyZSBwbG90dGVkLg0KDQoqIEZhY3RvcnMgYXJlIGVzcGVjaWFsbHkgdXNlZnVsIGlmIHdlIHdhbnQgdG8gZ3JvdXAgZGF0YSBieSBhIGZhY3RvciAoZS5nLiBjb3VudHJ5KSBmb3IgY291bnRpbmcgb3Igc3VtbWFyaXNpbmcuIEZvciBpbnN0YW5jZSwgIkhvbWUiIGFuZCAiUGhvbmUiIGVhY2ggb2NjdXIgdHdpY2UsIHdoZXJlYXMgIkxhdXJpZSIgYW5kICJFVCIgZWFjaCBvbmx5IG9jY3VyIG9uY2UuIA0KDQojIyMgVmVjdG9yaXNlZCBMYW5ndWFnZQ0KDQpWZWN0b3JzIGFyZW4ndCBqdXN0IGNvbnRhaW5lcnMgZm9yIGhvbW9nZW5lb3VzIGRhdGEuIEFzIFIgaXMgYSB2ZWN0b3Jpc2VkIGxhbmd1YWdlLCB0aGlzIG1lYW5zIG9wZXJhdGlvbnMgYXJlIGFwcGxpZWQgdG8gZWFjaCBlbGVtZW50IG9mIHRoZSB2ZWN0b3IgYXV0b21hdGljYWxseSwgd2l0aG91dCB0aGUgbmVlZCB0byBsb29wIHRocm91Z2ggdGhlIHZlY3Rvci4gDQoNClRoaXMgaXMgcG93ZXJmdWwgYXMgYXQgYSBsb3ctbGV2ZWwgYXMgY29tcHV0ZXIgY2hpcHMgYXJlIGdlbmVyYWxseSBvcHRpbWlzZWQgZm9yIHRoZXNlIHR5cGVzIG9mIGNhbGN1bGF0aW9ucyBbU0lNRF0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvU0lNRCkuDQoNCkxldCdzIGxvb2sgYXQgc29tZSBleGFtcGxlcw0KDQojIyMjIE11bHRpcGx5IGFuZCBFeHBvbmVudGlhdGUgTnVtZXJpYyBWZWN0b3JzDQoNCmBgYHtyIFlvdSBjYW4gbXVsdGlwbHkgYW5kIGV4cG9uZW50aWF0ZSB2ZWN0b3JzfQ0KDQpudW1lcmljX3ZlY3Rvcg0KDQpudW1lcmljX3ZlY3RvciozDQoNCm51bWVyaWNfdmVjdG9yXjINCg0KYGBgDQoNCllvdSBjYW4gYWxzbyBtdWx0aXBseSwgZGl2aWRlLCBhZGQsIGFuZCBzdWJ0cmFjdCB2ZWN0b3JzIG9mIHRoZSBzYW1lIGxlbmd0aC4NCg0KIyMjIyBEaXZpZGUgdmVjdG9ycyBvZiB0aGUgc2FtZSBsZW5ndGgNCg0KYGBge3IgRGl2aWRlIHZlY3RvcnMgb2YgdGhlIHNhbWUgbGVuZ3RofQ0KDQp4IDwtIHNlcShmcm9tID0gMSwgdG8gPSAyMCwgYnkgPSA0KQ0KDQp4DQoNCm51bWVyaWNfdmVjdG9yL3gNCg0KYGBgDQoNCg0KIyMjIyBTdWJ0cmFjdCBvciBBZGQgdmVjdG9ycyBvZiB0aGUgc2FtZSBsZW5ndGgNCg0KV2hhdCBoYXBwZW5zIHdoZW4geW91IHJ1biB0aGUgZm9sbG93aW5nIGxpbmUgb2YgY29kZT8NCg0KYGBge3IgWW91IGNhbiBzdWJ0cmFjdCB2ZWN0b3JzIG9mIHRoZSBzYW1lIGxlbmd0aH0NCg0KeCAtIG51bWVyaWNfdmVjdG9yDQoNCmBgYA0KDQoNCiMjIyBFeGVyY2lzZXMNCg0KRmlsbCBpbiB0aGUgY29kZSBjaHVua3MgdG8gYW5zd2VyIHRoZSBmb2xsb3dpbmcgcXVlc3Rpb25zDQoNCjEuIFRha2UgdGhlIGxhc3QgdHdvIGVsZW1lbnRzIG9mIHRoZSBudW1lcmljIHZlY3Rvcg0KDQpgYGB7ciBUYWtlIHRoZSBsYXN0IHR3byBlbGVtZW50cyBvZiB0aGUgbnVtZXJpYyB2ZWN0b3IsIGV2YWwgPSBGQUxTRX0NCg0KbnVtZXJpY192ZWN0b3JbXQ0KDQpgYGANCg0KMi4gVGFrZSB0aGUgZmlyc3QgYW5kIGxhc3QgZWxlbWVudHMgb2YgdGhlIGNoYXJhY3Rlcl92ZWN0b3IuIA0KDQpIaW50OiB5b3UgY2FuIHVzZSBgbGVuZ3RoKClgIHRvIGZpbmQgb3V0IGhvdyBtYW55IGVsZW1lbnRzIHRoZXJlIGFyZSBpbiB0aGUgY2hhcmFjdGVyIHZlY3Rvci4gDQoNCmBgYHtyIFRha2UgdGhlIGZpcnN0IGFuZCBsYXN0IGVsZW1lbnRzIG9mIHRoZSBjaGFyYWN0ZXJfdmVjdG9yLCBldmFsID0gRkFMU0V9DQoNCmNoYXJhY3Rlcl92ZWN0b3JbXQ0KDQpgYGANCg0KMy4gRGl2aWRlIHRoZSBudW1lcmljX3ZlY3RvciBieSAzDQoNCmBgYHtyIERpdmlkZSB0aGUgbnVtZXJpYyB2ZWN0b3IgYnkgMywgZXZhbCA9IEZBTFNFfQ0KDQpudW1lcmljX3ZlY3Rvcg0KDQpgYGANCg0KNC4gTXVsdGlwbGUgdGhlIG51bWVyaWNfdmVjdG9yIGJ5IHRoZSBuZXcgdmVjdG9yICd5Jw0KDQpgYGB7ciBNdWx0aXBsZSB0aGUgbnVtZXJpY192ZWN0b3IgYnkgdGhlIG5ldyB2ZWN0b3IgeX0NCg0KeSA8LSBjKDU6MSkNCg0KDQpgYGANCg0KDQo1LiBXaHkgZG8gdGhlIGZvbGxvd2luZyBsaW5lcyBvZiBjb2RlIG5vdCB3b3JrPw0KDQoNCmBgYHtyIFdoeSBkb2VzIGRpdmlkaW5nIG51bWVyaWNfdmVjdG9yIGJ5IHRoZSBvYmplY3QgdyBub3Qgd29yaywgZXZhbCA9IEZBTFNFfQ0KDQp3IDwtIGMoMTo0KQ0KDQpudW1lcmljX3ZlY3Rvci93DQoNCmBgYA0KDQoNCiMgQ1JBTiwgbGlicmFyeSwgcGFja2FnZXMsIGFuZCBmdW5jdGlvbnMNCg0KU28gZmFyLCB3ZSd2ZSBzZWVuIFIncyBjYXBhYmlsaXRpZXMgYXMgYSBsYXJnZSBjYWxjdWxhdG9yIGFuZCBhbHNvIGFzIGEgcGxhY2UgZm9yIHN0b3Jpbmcgb2JqZWN0cyBhbmQgdmVjdG9ycy4gSG93ZXZlciwgaXQgaXMgbXVjaCBtdWNoIG1vcmUgdGhhbiB0aGF0ISBPbmUgb2YgdGhlIHRoaW5ncyB0aGF0IG1ha2VzIFIgYW1hemluZyBpcyB0aGUgb3BlbiBzb3VyY2UgY29tbXVuaXR5IHN1cnJvdW5kaW5nIGl0Lg0KDQpUaGUgUiBjb21tdW5pdHkgd2hpY2ggaXMgbWFkZSB1cCBvZiBhY2FkZW1pY3MsIHN0YXRpc3RpY2lhbnMsIHNvY2lhbCBhbmQgcG9saXRpY2FsIHNjaWVudGlzdHMsIGVjb25vbWlzdHMsIGFuZCBkYXRhIHNjaWVudGlzdHMgdG8gbmFtZSBhIGZldywgYXJlIHJlc3BvbnNpYmxlIGZvciBhdXRob3JpbmcgYSB3aWRlIHZhcmlldHkgb2YgcGFja2FnZXMgKD4xNSwwMDApIHRoYXQgY2FuIGRvIGEgd2lkZSByYW5nZSBvZiBkYXRhIG1hbmlwdWxhdGlvbiwgdmlzdWFsaXNhdGlvbiwgYW5kIGFuYWx5c2lzIHRhc2tzLiANCg0KDQpUbyBnZXQgeW91ciBoZWFkIGFyb3VuZCB3aGF0IENSQU4sIGxpYnJhcnksIHBhY2thZ2VzLCBhbmQgZnVuY3Rpb25zIGFyZSBJIGZpbmQgaXQgaGVscGZ1bCB0byB0aGluayBvZiBib29rcy4gDQoNCg0KIyMgQ1JBTg0KDQpDUkFOIHN0YW5kcyBmb3IgdGhlICoqQyoqb21wcmVoZW5zaXZlICoqUioqICoqQSoqcmNoaXZlICoqTioqZXR3b3JrLiBJdCdzIGxpa2UgdGhlIFIgZXF1aXZhbGVudCBvZiB0aGUgQnJpdGlzaCBMaWJyYXJ5IG9yIExpYnJhcnkgb2YgQ29uZ3Jlc3MuIEl0IGhvbGRzIGEgY29weSBvZiBldmVyeSBwYWNrYWdlIChib29rKSBhbmQgYWxsIHRoZSB2ZXJzaW9ucyBvZiBSLiANCg0KIVtdKHBpY3R1cmVzL0NSQU5fcGFja2FnZXNfZXhhbXBsZS5wbmcpe3dpZHRoPTY1MHB4fQ0KDQojIyBMaWJyYXJ5DQoNCk9uIHlvdXIgY29tcHV0ZXIgeW91J2xsIGhhdmUgYSBsb2NhbCBsaWJyYXJ5IHdpdGggY29waWVzIG9mIHRoZSBwYWNrYWdlcyB5b3UndmUgaW5zdGFsbGVkIGZyb20gQ1JBTiAoeW91ciBob21lIG9mZmljZSBib29rIHNoZWxmKS4NCg0KIyMjIFdoYXQncyBvbiB5b3VyIGJvb2tzaGVsZj8NCg0KKiBDbGljayBvbiB0aGUgJ1BhY2thZ2VzJyB0YWIgaW4gdGhlIGxvd2VyIHJpZ2h0IGhhbmQgcGFuZWwgKFE0IGZyb20gYmVmb3JlKS4gWW91IGNhbiBzZWUgd2hhdCBwYWNrYWdlcyBhcmUgaW4geW91ciBsaWJyYXJ5LCBhIHNob3J0IGRlc2NyaXB0aW9uIG9mIHdoYXQgdGhleSBkbywgYW5kIHRoZSBwYWNrYWdlIHZlcnNpb24uIA0KKiBUaGUgcGFja2FnZXMgdGhhdCBhcmUgbG9hZGVkIGhhdmUgYSBjaGVjayBtYXJrIGluIHRoZSBib3ggb24gdGhlIGxlZnQuIEFzIGJlZm9yZSwgdGhlcmUgYXJlIHNldmVyYWwgcGFja2FnZXMgdGhhdCBhcmUgYXV0b21hdGljYWxseSBsb2FkZWQgZWFjaCB0aW1lIHlvdSBzdGFydCBhbiBSIHNlc3Npb24sIGUuZy4gYGJhc2VgIHBhY2thZ2UuICANCg0KKiBBbHRob3VnaCBpdCBpcyBwb3NzaWJsZSB0byBsb2FkIGFuZCBpbnN0YWxsIHlvdXIgcGFja2FnZXMgZnJvbSBoZXJlLCBJIHJlY29tbWVuZCB1c2luZyB0aGUgZnVuY3Rpb25zIHNob3duIGJlbG93IGluc3RlYWQuIFRoaXMgd2F5LCBzb21lb25lZWxzZSBvciAqKmZ1dHVyZSB5b3UqKiBrbm93cyBleGFjdGx5IHdoYXQgcGFja2FnZXMgdGhleSBuZWVkIHRvIHJ1biB0aGUgYW5hbHlzZXMuIA0KDQoqIFlvdSBzaG91bGQgbG9hZCB0aGUgcGFja2FnZXMgeW91IHdpbGwgdXNlIGF0IHRoZSB0b3Agb2YgeW91ciBzY3JpcHQsIHNvIHRoYXQgZnV0dXJlIHlvdSBvciB5b3VyIGNvbGxlYWd1ZSBrbm93cyB3aGF0IG5lZWRzIHRvIGJlIGluc3RhbGxlZC9sb2FkZWQuDQoNCiMjIyBJbnN0YWxsaW5nIFBhY2thZ2VzIG9uIGEgUGVyc29uYWwgQ29tcHV0ZXINCg0KKiBBIHBhY2thZ2UgbmVlZHMgdG8gYmUgaW5zdGFsbGVkIG9ubHkgb25jZSBhbmQgcmVxdWlyZXMgYW4gaW50ZXJuZXQgY29ubmVjdGlvbiB3aGljaCBhbGxvd3MgeW91ciBjb21wdXRlciB0byBjb21tdW5pY2F0ZSB3aXRoIHRoZSBDUkFOIHNlcnZlci4gDQoNCiogWW91IG1heSB3aXNoIHRvIGluc3RhbGwgYSBwYWNrYWdlIHdpdGggdGhlIGFkZGl0aW9uYWwgYXJndW1lbnQ6IGBkZXBlbmRlbmNpZXMgPSBUUlVFYCwgdGhpcyB3aWxsIGFsc28gaW5zdGFsbCBhbnkgcGFja2FnZXMgdGhhdCB0aGUgcGFja2FnZSBkZXBlbmRzIG9uLg0KDQoqIE9uIHlvdXIgcGVyc29uYWwgY29tcHV0ZXIsIHlvdSBjYW4gaW5zdGFsbCBhIHBhY2thZ2UgdG8geW91ciBsb2NhbCBsaWJyYXJ5IGZyb20gQ1JBTiBieSB1bmNvbW1lbnRpbmcgYW5kIHJ1bm5pbmcgdGhlIGZvbGxvd2luZzoNCg0KYGBge3IgSW5zdGFsbGluZyBwYWNrYWdlcyBkaXJlY3RseSwgZXZhbCA9IEZBTFNFfQ0KDQojIGluc3RhbGwucGFja2FnZXMoInRpZHl2ZXJzZSIpDQoNCiMgaW5zdGFsbC5wYWNrYWdlcygiZ2dwbG90MiIsIGRlcGVuZGVuY2llcyA9IFRSVUUpDQoNCmBgYA0KDQpIb3dldmVyLCBpZiB5b3UgYXJlIG9uIGEgZ292ZXJubWVudCBsYXB0b3Agd2l0aG91dCBlbGV2YXRlZCBhY2Nlc3MgcmlnaHRzLCByZWFkIGZ1cnRoZXIuLi4NCg0KIyMjIEluc3RhbGxpbmcgUGFja2FnZXMgb24gYSBHb3Zlcm5tZW50IENvbXB1dGVyDQoNCiogT24geW91ciBnb3Zlcm5tZW50IGxhcHRvcCwgeW91IHdpbGwgbmVlZCB0byBwdXQgaW4gYSBTZXJ2aWNlIERlc2sgU29mdHdhcmUgUmVxdWVzdCBmb3IgYW55IHBhY2thZ2VzIHlvdSB3YW50IGluc3RhbGxlZC4gDQoqIEFzIGEgc3RhbmRhcmQgdXNlciwgeW91IGFyZSB1bmFibGUgdG8gcnVuIFIgcGFja2FnZXMgdGhhdCB5b3UgZG93bmxvYWQgYXMgaXQgaW5zdGFsbHMgdGhlbSB0byB5b3VyIERvY3VtZW50cyBmb2xkZXIuIEJlY2F1c2Ugb2YgcmVzdHJpY3Rpb25zIG9uIHRoZSBnb3Zlcm5tZW50IGxhcHRvcHMsIGl0IGlzIHRoZW4gdW5hYmxlIHRvIHJ1biB0aGUgcGFja2FnZSBmcm9tIHRoaXMgbG9jYXRpb24gYmVjYXVzZSB0aGUgRExMIGZpbGVzIGl0IGNvbnRhaW5zIGFyZSBibG9ja2VkLg0KDQoqIEFzIGEgcmVzdWx0LCB0aGUgUiBpbnN0YWxsYXRpb24gb2Z0ZW4gY29tZXMgd2l0aCBtYW55IG9mIHRoZSBwYWNrYWdlcyB5b3UnbGwgbmVlZCBwcmUtaW5zdGFsbGVkLiBGb3IgYW55IG90aGVyIHBhY2thZ2VzIHlvdSB3aXNoIHRvIGluc3RhbGwsIHlvdSBjYW4gcHV0IGluIGEgU2VydmljZSBEZXNrIHJlcXVlc3QuIA0KDQojIyMgRXJyb3JzIEluc3RhbGxpbmcgUGFja2FnZXMgdG8gYSBHb3Zlcm5tZW50IENvbXB1dGVyDQoNCklmIHlvdSBkbyBpbnN0YWxsIHBhY2thZ2VzIHlvdXJzZWxmLCBpdCBpcyBoaWdobHkgbGlrZWx5IHRoYXQgeW91IHdpbGwgZ2V0IHRoaXMgZXJyb3IgaWYgeW91IGluc3RhbGwgcGFja2FnZXMgYW5kIGxvYWQgdGhlbSBmcm9tIHRoZSBpbnRlcm5ldC4gDQoNCj4gIkVycm9yOiBwYWNrYWdlIG9yIG5hbWVzcGFjZSBsb2FkIGZhaWxlZCBmb3Ig4oCYZ2dwbG90MuKAmSBpbiBpbkRMKHgsIGFzLmxvZ2ljYWwobG9jYWwpLCBhcy5sb2dpY2FsKG5vdyksIC4uLik6DQogdW5hYmxlIHRvIGxvYWQgc2hhcmVkIG9iamVjdCAnQzovVXNlcnMvbC1iYWtlci9Eb2N1bWVudHMvUi93aW4tbGlicmFyeS8zLjYvcmxhbmcvbGlicy94NjQvcmxhbmcuZGxsJzoNCiAgTG9hZExpYnJhcnkgZmFpbHVyZTogIFRoaXMgcHJvZ3JhbSBpcyBibG9ja2VkIGJ5IGdyb3VwIHBvbGljeS4gRm9yIG1vcmUgaW5mb3JtYXRpb24sIGNvbnRhY3QgeW91ciBzeXN0ZW0gYWRtaW5pc3RyYXRvci4iDQoNCg0KSWYgeW91IGRvIHRyeSB0byBpbnN0YWxsIHBhY2thZ2VzIGFuZCBpZiB5b3UgZ2V0IHRoZSBhYm92ZSBlcnJvciB5b3UgY2FuIGZpeCBpdCBieSAqKmRlbGV0aW5nIHlvdXIgUiBmb2xkZXIgZnJvbSBEb2N1bWVudHMqKi4gUiB3aWxsIHRoZW4gcmV0dXJuIHRvIGxvb2tpbmcgZm9yIHBhY2thZ2VzIHRoYXQgY29tZSBzdXBwbGllZCB3aXRoIHlvdXIgZGVwYXJ0bWVudCdzIFIgZGlzdHJpYnV0aW9uLiANCg0KIyMjIExvYWRpbmcgcGFja2FnZXMNCg0KSW4gb3JkZXIgdG8gdXNlIHRoZSBwYWNrYWdlIHlvdSBuZWVkIHRvIGxvYWQgaXQgdG8geW91ciB3b3Jrc3BhY2UuIFRoaXMgbmVlZHMgdG8gYmUgZG9uZSBlYWNoIHRpbWUgeW91IHN0YXJ0IGEgbmV3IFJTdHVkaW8gc2Vzc2lvbiBvciBwcm9qZWN0LiBUaGluayBvZiBpdCBhcyB0YWtpbmcgdGhlIGJvb2sgeW91IHdpbGwgdXNlIG9mZiB5b3VyIGJvb2sgc2hlbGYgdG8gcGxhY2UgbmV4dCB0byB5b3Ugb24gdGhlIGRlc2suDQoNCkluIHRoaXMgY2FzZSwgYHRpZHl2ZXJzZWAgaXMgYSBtZXRhLXBhY2thZ2UsIHdoaWNoIGFjdHVhbGx5IGNvbnRhaW5zIHNldmVyYWwgaW5kaXZpZHVhbCBwYWNrYWdlcyBpbmNsdWRpbmcgYGRwbHlyYCwgYGZvcmNhdHNgLCBldGMuLCBidXQgbW9yZSBvbiB0aG9zZSBsYXRlci4gVGhlIGB0aWR5dmVyc2VgIG1ldGFwYWNrYWdlIGlzIGluIHlvdXIgbGlicmFyeSBhbHJlYWR5IHNvIHdlIGNhbiBzaW1wbHkgbWFrZSBhIGNhbGwgdG8gbG9hZCB0aGVtLiANCg0KYGBge3IgSW1wb3J0aW5nIFBhY2thZ2VzfQ0KDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCg0KYGBgDQoNCkFsYXMsIHRoZXJlIGFyZSBub3QgZW5vdWdoIG5hbWVzIHRvIG1ha2UgZWFjaCBmdW5jdGlvbiBpbiBldmVyeSBwYWNrYWdlIHVuaXF1ZS4gVGhlICJDb25mbGljdHMiIGxpbmUgdGhhdCBpcyBwcmludGVkIHRlbGxzIHVzIHRoYXQgdGhlIGBkcGx5cmAgZnVuY3Rpb24gYGZpbHRlcmAgd2lsbCBtYXNrIHRoZSBgc3RhdHNgIHBhY2thZ2UgZnVuY3Rpb24gYGZpbHRlcmAuIA0KDQpJZiB3ZSB3YW50IHRvIGJlIGNvbXBsZXRlbHkgYWNjdXJhdGUsIHdlIGNhbiBzcGVjaWZ5IHRoZSBwYWNrYWdlIGFuZCBmdW5jdGlvbiB1c2luZyB0aGUgZm9sbG93aW5nIGZvcm0gYDxwYWNrYWdlX25hbWU+Ojo8ZnVuY3Rpb25fbmFtZT5gLCBlLmcuIGBkcGx5cjo6ZmlsdGVyKClgLiANCg0KSWYgd2UgZm9sbG93IHRoZSByZWNpcGUgYm9vayBhbmFsb2d5LCB0aGlzIGlzIGxpa2Ugc2F5aW5nIHdlIHdhbnQgdGhlIGxhc2FnbmEgcmVjaXBlIGZyb20gYGphbWllX29saXZlcjo6bGFzYWduYWAgc28gdGhhdCBpdCBpc24ndCBjb25mdXNlZCB3aXRoIHRoZSBgbmlnZWxsYV9sYXdzb246Omxhc2FnbmFgIHJlY2lwZS4gIA0KDQojIyBQYWNrYWdlcw0KDQohW10ocGljdHVyZXMvcGFja2FnZV9ib29rLmpwZyl7d2lkdGg9MjUwcHh9DQoNCllvdSBjYW4gdGhpbmsgb2YgYSBwYWNrYWdlIGxpa2UgYSBib29rIG9uIGEgcGFydGljdWxhciBzdWJqZWN0LiBFYWNoICoqcGFja2FnZSoqIGlzIGRlc2lnbmVkIHRvIGRvIGEgc3BlY2lmaWMgc2V0IG9mIHRhc2tzIChlLmcuIGRhdGEgbWFuaXB1bGF0aW9uLCBpbXBsZW1lbnQgbGluZWFyIG1vZGVscywgZHJhdyBnZW9ncmFwaGljYWwgbWFwcywgZXRjLikuIEVhY2ggdGFzayBpcyBpbXBsZW1lbnRlZCB1c2luZyBhICoqZnVuY3Rpb24qKiwgd2hpY2ggaXMgYSBzZXQgb2Ygc3RhdGVtZW50cyBvcmdhbmlzZWQgdG8gY29tcGxldGUgdGhlIHRhc2suIA0KDQojIyBGdW5jdGlvbnMNCg0KQSBmdW5jdGlvbiBpcyBsaWtlIGEgcmVjaXBlIGZyb20gYSBib29rLiBJdCBpcyBkZXNpZ25lZCB0byBtYWtlIG9uZSBzcGVjaWZpYyB0aGluZywgZS5nLiBjdXBjYWtlcyBvciBzdGVhayBhbmQga2lkbmV5IHBpZS4gVGhlIGZ1bmN0aW9uIHRha2VzIGFyZ3VtZW50cyAoZS5nLiBpbmdyZWRpZW50cykgYW5kIHRoZW4gY2FycmllcyBvdXQgYSBzZXJpZXMgb2Ygc3RlcHMgd2hlcmUgdGhlIGluZ3JlZGllbnRzIGFyZSBtb2RpZmllZCwgY29va2VkLCBjb21iaW5lZCwgZXRjLiB0byBjcmVhdGUgdGhlIGZpbmFsIHJlY2lwZS4gDQoNClNvbWUgb2YgdGhlc2UgYXJndW1lbnRzIHdpbGwgYmUgb3B0aW9uYWwgKGUuZy4gYWRkIG9yIGRvbid0IGFkZCBjaW5uYW1vbiksIHdoZXJlYXMgb3RoZXIgYXJndW1lbnRzIHdpbGwgYmUgcmVxdWlyZWQgZm9yIHRoZSBmdW5jdGlvbiB0byBydW4gKGUuZy4geW91IGNhbid0IG1ha2UgdGhlIGNha2Ugd2l0aG91dCBmbG91ciEpLg0KDQohW10ocGljdHVyZXMvcmVjaXBlX2Z1bmN0aW9uLnBuZyl7d2lkdGg9NTAwcHh9DQoNCkZ1bmN0aW9ucyBmb2xsb3cgdGhlIGZvcm06DQoNCiogYGZ1bmN0aW9uTmFtZShhcmd1bWVudDEgPSB2YWx1ZTEsIGFyZ3VtZW50MiA9IHZhbHVlMiwgYW5kIHNvIG9uKWANCg0KTGV0J3MgdGFrZSBhIGxvb2sgYXQgc29tZSBvZiB0aGUgYnVpbHQtaW4gZnVuY3Rpb25zIFIgaGFzIGZvciBjYXJyeWluZyBvdXQgYmFzaWMgc3RhdGlzdGljcy9hbmFseXNpcywgc3RhcnRpbmcgd2l0aCBgc2VxKClgLiANCg0KIyMjIEhvdyBmdW5jdGlvbnMgd29yazogdGhlIGBzZXEoKWAgZnVuY3Rpb24NCg0KTGV04oCZcyB0cnkgdXNpbmcgYHNlcSgpYCB3aGljaCBtYWtlcyByZWd1bGFyIHNlcXVlbmNlcyBvZiBudW1iZXJzIGFuZCwgd2hpbGUgd2XigJlyZSBhdCBpdCwgZGVtbyBtb3JlIGhlbHBmdWwgZmVhdHVyZXMgb2YgUlN0dWRpby4NCg0KKiBUeXBlIGBzZWAgYW5kIGhpdCBUQUIuIEEgcG9wIHVwIHNob3dzIHlvdSBwb3NzaWJsZSBjb21wbGV0aW9ucy4gDQoNCmBgYHtyIEF1dG9jb21wbGV0aW5nIHVzaW5nIFRBQiwgZXZhbCA9IEZBTFNFfQ0KDQpzZQ0KDQpgYGANCg0KDQoqIFNwZWNpZnkgc2VxKCkgYnkgdHlwaW5nIG1vcmUgdG8gc3BlY2lmeSB0aGUgZnVuY3Rpb24gb3IgdXNpbmcgdGhlIHVwL2Rvd24gYXJyb3dzIHRvIHNlbGVjdC4gTm90aWNlIHRoZSBmbG9hdGluZyBoZWxwIGJveCB0aGF0IHBvcHMgdXAgdG8gcmVtaW5kIHlvdSBvZiB0aGUgZnVuY3Rpb27igJlzIGFyZ3VtZW50cy4gDQoNCiogSWYgeW91IHdhbnQgZXZlbiBtb3JlIGhlbHAsIHByZXNzIEYxIGFzIGRpcmVjdGVkIHRvIGdldCB0aGUgZnVsbCBkb2N1bWVudGF0aW9uIGluIHRoZSBoZWxwIHRhYiBvZiB0aGUgbG93ZXIgcmlnaHQgcGFuZS4gDQpZb3UgY2FuIGFsc28gYWNjZXNzIHRoZSBoZWxwIGZpbGUgZm9yIGEgZnVuY3Rpb24gYnkgdHlwaW5nIGA/c2VxYC4gDQoNCiogTm93IG9wZW4gdGhlIHBhcmVudGhlc2VzIGFuZCBub3RpY2UgdGhlIGF1dG9tYXRpYyBhZGRpdGlvbiBvZiB0aGUgY2xvc2luZyBwYXJlbnRoZXNpcyBhbmQgdGhlIHBsYWNlbWVudCBvZiBjdXJzb3IgaW4gdGhlIG1pZGRsZS4gVHlwZSB0aGUgYXJndW1lbnRzIDEsIDEwIGFuZCBoaXQgcmV0dXJuLiBSU3R1ZGlvIGFsc28gZXhpdHMgdGhlIHBhcmVudGhldGljYWwgZXhwcmVzc2lvbiBmb3IgeW91Lg0KDQpgYGB7ciBVc2luZyB0aGUgZnVuY3Rpb24gc2VxfQ0KDQpzZXEoMSwxMCkNCg0KYGBgDQoNCkxldCdzIHRha2UgYSBjbG9zZXIgbG9vayBhdCB0aGUgaGVscCBmaWxlIGZvciBgc2VxKClgLg0KDQpgYGB7ciBIZWxwZmlsZSBmb3Igc2VxKCksIGV2YWwgPSBGQUxTRX0NCg0KP3NlcQ0KDQpgYGANCg0KIVtdKHBpY3R1cmVzL1NlcV9oZWxwZmlsZS5wbmcpe3dpZHRoPTY1MHB4fQ0KDQojIyMjIEZ1bmN0aW9uIGhlbHAgZmlsZXMNCg0KRXZlcnkgaGVscCBmaWxlIHdpbGwgaGF2ZSBhIHNlcmllcyBvZiBzZWN0aW9ucyBkZXNjcmliaW5nIHdoYXQgdGhlIGZ1bmN0aW9uIGRvZXMuIEkgZ2VuZXJhbGx5IGZvY3VzIGZpcnN0IG9uOiAqKkRlc2NyaXB0aW9uKiosICoqVXNhZ2UqKiwgKipBcmd1bWVudHMqKiwgYW5kICoqRXhhbXBsZXMqKi4gDQoNCiogKipEZXNjcmlwdGlvbioqDQoNCkZvciBleGFtcGxlLCBpbiB0aGUgaGVscGZpbGUgZm9yIGBzZXEoKWAgdW5kZXIgKipEZXNjcmlwdGlvbioqLCBpdCB0ZWxscyB1cyBpdCBpcyBhIGZ1bmN0aW9uIHRvICJHZW5lcmF0ZSByZWd1bGFyIHNlcXVlbmNlcyIuIA0KDQoqICoqVXNhZ2UqKg0KDQpXZSBjYW4gc2VlIHRoYXQgYHNlcSgpYCB0YWtlcyB0aGUgYXJndW1lbnRzIGBmcm9tYCwgYHRvYCwgYW5kIGBieWAsIGFuZCB0aGUgb3B0aW9uYWwgYXJndW1lbnRzIGBsZW5ndGgub3V0YCBhbmQgYGFsb25nLndpdGhgLiANCg0KKiAqKkFyZ3VtZW50cyoqDQoNCkhlcmUsIHdlIGNhbiBmaW5kIG91dCB3aGF0IHRoZXNlIGFyZ3VtZW50cyBhcmU6DQoNCiAgLSBgZnJvbSwgdG9gOiB0aGUgc3RhcnRpbmcgYW5kIG1heGltYWwgZW5kIHZhbHVlcyBvZiB0aGUgc2VxdWVuY2UuDQogIC0gYGJ5YCBudW1iZXI6IGluY3JlbWVudCBvZiB0aGUgc2VxdWVuY2UuDQogIA0KSW4gdGhlIGNvZGUgd2UgdXNlZCBhYm92ZSBpbiBzZXF1ZW5jZSwgd2UgZ2VuZXJhdGVkIGEgc2VxdWVuY2Ugb2YgbnVtYmVycyBgZnJvbWAgMSBgdG9gIDEwLiBJbiB0aGlzIGNhc2Ugd2UgZGlkIG5vdCBzdXBwbHkgYSB2YWx1ZSBmb3IgYGJ5YCwgc28gaXQgdG9vayB0aGUgZGVmYXVsdCB2YWx1ZSwgd2hpY2ggaW4gdGhpcyBjYXNlIGlzIDEuDQoNCiMjIyMgSG93IGFyZSBmdW5jdGlvbiBhcmd1bWVudHMgcmVzb2x2ZWQ/DQoNCldoYXQgaGFwcGVucyBpZiB3ZSB0cnk6DQoNCmBgYHtyIEhvdyBhcmUgZnVuY3Rpb24gYXJndW1lbnRzIHJlc29sdmVkIHBhcnQgMSwgZXZhbCA9IEZ9DQoNCnNlcSgxMCwxKQ0KDQpgYGANCg0KQW5kIHdoYXQgYWJvdXQ6DQoNCmBgYHtyIEhvdyBhcmUgZnVuY3Rpb24gYXJndW1lbnRzIHJlc29sdmVkIHBhcnQgMiwgZXZhbCA9IEZ9DQoNCnNlcSh0byA9IDEwLCBmcm9tID0gMSkNCg0KYGBgDQoNClRoZSBhYm92ZSBkZW1vbnN0cmF0ZXMgc29tZXRoaW5nIGFib3V0IGhvdyBSIHJlc29sdmVzIGZ1bmN0aW9uIGFyZ3VtZW50cy4gWW91IGNhbiBhbHdheXMgc3BlY2lmeSBpbiBgbmFtZSA9IHZhbHVlYCBmb3JtLiBCdXQgaWYgeW91IGRvIG5vdCwgUiBhdHRlbXB0cyB0byByZXNvbHZlIGJ5IHBvc2l0aW9uLiANCg0KU28gYWJvdmUsIGZpcnN0IGl0IGlzIGFzc3VtZWQgdGhhdCB3ZSB3YW50IGEgc2VxdWVuY2UgZnJvbSA9IDEgdGhhdCBnb2VzIHRvID0gMTAuIFRoZW4gaWYgd2Ugc3dhcCB0aGUgbnVtYmVycyBpdCBpcyBhc3N1bWVkIHdlIHdhbnQgdG8gc2VxdWVuY2UgZnJvbSA9IDEwIHRoYXQgZ29lcyB0byA9IDEuIElmIHdlIG5hbWUgdGhlIGFyZ3VtZW50cyBleHBsaWNpdGx5IHVzaW5nIGBuYW1lID0gdmFsdWVgLCB0aGUgb3JkZXIgb2YgdGhlIGFyZ3VtZW50cyBkb2Vzbid0IG1hdHRlci4gDQoNCiMjIyMgUHJpbnRpbmcgb2JqZWN0cyBhbmQgdmlld2luZyB5b3VyIHdvcmtzcGFjZQ0KDQpJZiB3ZSB3YW50IHRvIHN0b3JlIG91ciBvdXRwdXQgaW4gYW4gb2JqZWN0IGFuZCBzZWUgaXQgaW4gdGhlIHNhbWUgbGluZSwgd2UgY2FuIHVzZToNCg0KYGBge3IgU3RvcmluZyBhbmQgcHJpbnRpbmcgb2JqZWN0cyB1c2luZyBwYXJlbnRoZXNlcywgZXZhbCA9IEZBTFNFfQ0KDQooeSA8LSBzZXEoZnJvbSA9IDEsIHRvID0gMTApKQ0KDQpgYGANCg0KTGV0J3MgdGFrZSBhIGxvb2sgYXQgb3VyIHdvcmtzcGFjZSBhbmQgc2hvd2Nhc2UgYSBmdW5jdGlvbiB0aGF0IGRvZXNuJ3QgcmVxdWlyZSBhbnkgYXJndW1lbnRzLiANCg0KYGBge3IgVXNlIGxzKCkgdG8gc2VlIHdoYXQgaXMgaW4geW91ciB3b3Jrc3BhY2UsIGV2YWwgPSBGQUxTRX0NCg0KbHMoKQ0KDQpgYGANCg0KSWYgeW91IHdhbnQgdG8gcmVtb3ZlIHRoZSB2ZWN0b3IgbmFtZSBgeWAgeW91IGNhbiB1c2UNCg0KYGBge3IgUmVtb3ZpbmcgdmVjdG9ycyB1c2luZyBybSgpLCBldmFsID0gRkFMU0V9DQoNCnJtKHkpDQoNCmBgYA0KDQpJZiB5b3Ugd2FudCB0byByZW1vdmUgZXZlcnl0aGluZyBpbiB5b3VyIHdvcmtzcGFjZSB5b3UgY2FuIHVzZToNCg0KYGBge3IgUmVtb3ZlIGV2ZXJ5dGhpbmcgdXNpbmcgcm0oKSBhbmQgbHMoKX0NCg0Kcm0obGlzdCA9IGxzKCkpDQoNCmBgYA0KDQpZb3UgbWF5IHdhbnQgdG8gZG8gdGhpcyBhdCB0aGUgZW5kIG9mIGFuIGFuYWx5c2lzIGJlZm9yZSB5b3Ugc3RhcnQgb24gYW5vdGhlciBwcm9qZWN0LiANCg0KIyBEYXRhIGZyYW1lcyBhbmQgdGliYmxlcw0KDQpBbnl0aW1lIHlvdXIgZGF0YSBpcyByZWN0YW5ndWxhciwgc3ByZWFkc2hlZXQtbGlrZSBkYXRhLCB0aGUgZGVmYXVsdCBkYXRhIGZvcm1hdCBpbiBSIGlzIGEgZGF0YSBmcmFtZS4gRGF0YSBmcmFtZXMgY2FuIGhvbGQgdmFyaWFibGVzIG9mIGRpZmZlcmVudCB0eXBlcy4gV2hlcmUgZWFjaCBjb2x1bW4gb2YgdGhlIGRhdGEsIGlzIGVzc2VudGlhbGx5IGEgdmVjdG9yLCBzdWNoIGFzIG51bWVyaWMgZGF0YSAoR0RQKSwgY2hhcmFjdGVyIGRhdGEgKGNvdW50cnkgbmFtZSksIGFuZCBjYXRlZ29yaWNhbCBpbmZvcm1hdGlvbiAoaW5mZWN0ZWQgdnMuIHVuaW5mZWN0ZWQpLiANCg0KRGF0YSBmcmFtZXMgYXJlIGV4dHJlbWVseSB1c2VmdWwgYW5kIG1hbnkgZnVuY3Rpb25zIGFyZSBzZXQgdXAgdG8gdGFrZSBhIGRhdGEgZnJhbWUgZm9yIHRoZSBgZGF0YSA9YCBhcmd1bWVudC4gVGhlIGB0aWR5dmVyc2VgIHBhY2thZ2VzLCB3aGljaCBpbmNsdWRlIGBkcGx5cmAgYW5kIGBnZ3Bsb3QyYCB3b3JrIHdpdGggYSBzcGVjaWFsIHR5cGUgb2YgZGF0YSBmcmFtZSwgY2FsbGVkIGEgInRpYmJsZSIuDQoNCg0KIyMgR2FwbWluZGVyIERhdGENCg0KT3VyIGRhdGEgY29tZXMgZnJvbSB0aGUgR2FwbWluZGVyIGZvdW5kYXRpb24sIGFuIG9yZ2FuaXphdGlvbiBkZWRpY2F0ZWQgdG8gZWR1Y2F0aW5nIHRoZSBwdWJsaWMgYnkgdXNpbmcgZGF0YSB0byBkaXNwZWwgY29tbW9uIG15dGhzIGFib3V0IHRoZSBzby1jYWxsZWQgZGV2ZWxvcGluZyB3b3JsZC4gVGhlIGRhdGFzZXQgd2Ugd2lsbCB1c2UgaXMgb25lIHRoYXQgaGFzIGJlZW4gY29tYmluZWQgZnJvbSB0aGUgZ2FwbWluZGVyIGRhdGEgc2V0IGZyb20gdGhlIGBnYXBtaW5kZXJgIHBhY2thZ2UsIGFuZCB0aGUgZ2FwbWluZGVyIGRhdGEgc2V0IGZyb20gdGhlIGBkc2xhYnNgIHBhY2thZ2UuIA0KDQojIyBSZWFkaW5nIGluIHRoZSBkYXRhDQoNCkJlZm9yZSB5b3UgcmVhZCBpbiBhIGRhdGEgZmlsZSB5b3Ugd2FudCB0byBhc2sgeW91cnNlbGYgdHdvIHF1ZXN0aW9uczoNCg0KMS4gV2hhdCB0eXBlIG9mIGZpbGUgaXMgaXQ/DQoyLiBXaGVyZSBpcyB0aGUgZmlsZSBzdG9yZWQ/DQoNCkluIHRoaXMgY2FzZSwgd2UgYXJlIGdvaW5nIHRvIHJlYWQgaW4gYSBgLmNzdmAgKGNvbW1hIHNlcGFyYXRlZCB2YWx1ZSkgZmlsZSBjYWxsZWQgYGdhcG1pbmRlci5jc3ZgLiANCg0KVGhlIHRpZHl2ZXJzZSBjb21lcyB3aXRoIGEgbnVtYmVyIG9mIHVzZWZ1bCBmdW5jdGlvbnMgZm9yIHJlYWRpbmcgaW4gZGF0YS4gRm9yIHNvbWUgb2YgdGhlIG1vc3QgY29tbW9uIGZpbGVzIHlvdSB3b3JrIHdpdGggeW91IGNhbiB1c2U6DQoNCiAqIGByZWFkX2NzdmA6IHJlYWRzIGluIGEgY3N2IGZpbGUNCiAqIGByZWFkX2V4Y2VsYDogZnJvbSB0aGUgYHJlYWR4bGAgcGFja2FnZSByZWFkcyBpbiBhbiBleGNlbCBmaWxlICgueGxzIGFuZCAueGxzeCkuIFBvc3NpYmxlIHRvIGFkZCB0aGUgc2hlZXQgbnVtYmVyIG9yIG5hbWUgeW91IHdpc2ggdG8gZXh0cmFjdC4gQ2hlY2sgb3V0IHRoZSBhcmd1bWVudHMgaW4gdGhlIGhlbHBmaWxlIHVzaW5nIGA/cmVhZF9leGNlbGAuIA0KIA0KYW5kIG11Y2gsIG11Y2gsIG1vcmUhIElmIHlvdSBhcmUgbG9va2luZyBmb3IgYW5vdGhlciBmaWxlIHR5cGUgSSBoaWdobHkgcmVjb21tZW5kIGNoZWNraW5nIG91dCB0aGlzIHNlY3Rpb24gZnJvbSBKZW5ueSBCcnlhbidzIFVCQyBzdGF0cyBjb3Vyc2UgW1N0YXQ1NDUgSW1wb3J0IGFuZCBFeHBvcnRdKGh0dHBzOi8vc3RhdDU0NS5jb20vaW1wb3J0LWV4cG9ydC5odG1sKSBvciBsb29raW5nIG1vcmUgZ2VuZXJhbGx5IGludG8gdGhlIGByZWFkcmAgcGFja2FnZS4gVGhlcmUgYXJlIG5pY2Ugb3B0aW9ucyBmb3IgcmVtb3ZpbmcgbGluZXMgb2YgbWV0YSBkYXRhIChlLmcuIHJhbWJsZXMgYXQgdGhlIGhlYWQgb2YgYW4gZXhjZWwgc3ByZWFkc2hlZXQpIGFuZCBvdGhlciBvcHRpb25zIGZvciBtZXNzaWVyIGRhdGEgZnJhbWVzLg0KIA0KIyMjIFJlYWRpbmcgaW4gdGhlIGRhdGEgdXNpbmcgdGhlIGByZWFkX2AgZnVuY3Rpb25zDQoNClRoZSBmdW5jdGlvbnMgZm9yIHJlYWRpbmcgaW4gdGhlIGRhdGEgdGFrZSB0aGUgc2FtZSBiYXNpYyBmb3JtDQogDQpgYGB7ciBMYXlvdXQgb2YgdGhlIHJlYWQgZnVuY3Rpb25zLCBldmFsID0gRkFMU0V9DQoNCm15X2ZpbGUgPC0gZmlsZS5wYXRoKCJkYXRhIiwgImdhcG1pbmRlci5jc3YiKQ0KDQpnYXBtaW5kZXIgPC0gcmVhZF9jc3YoZmlsZSA9IG15X2ZpbGUpDQoNCmBgYA0KDQoqIEZpcnN0IHlvdSBuZWVkIHRvIHNwZWNpZnkgdGhlIG5hbWUgb2YgdGhlIGRhdGEgZnJhbWUgeW91IHdhbnQgdG8gc3RvcmUgeW91ciBkYXRhIGluLiANCg0KKiBUaGVuIHlvdSBzcGVjaWZ5IHRoZSBmaWxlIG5hbWUgKGBmaWxlID0gYCBvciBpbiByZWFkeGwgYHBhdGggPSBgKSAoZG9uJ3QgZm9yZ2V0IHRoZSBmaWxlIGZvcm1hdCBlLmcuIGAuY3N2YCkgYW5kIHRoZSBsb2NhdGlvbiB3aGVyZSBpdCBpcyBzdG9yZWQgaW4gcXVvdGVzLiANCg0KSW4gdGhpcyBjYXNlIHRoZSBmaWxlIGlzIHN0b3JlZCBpbiB0aGUgZm9sZGVyICJkYXRhIiB3aGljaCBpcyBwYXJ0IG9mIHRoZSBJbnRyb1IgY291cnNlIG1hc3RlciBmb2xkZXIgeW91IHdlcmUgc2VudC4gSGVyZSwgeW91J2xsIG5vdGljZSB0aGF0IHdlIGFyZSB1c2luZyBhIHJlbGF0aXZlIHBhdGgsIHRoYXQgaXMgdGhlIGxvY2F0aW9uIG9mIHRoZSBkYXRhIGlzIHNwZWNpZmllZCBpbiByZWxhdGlvbiB0byBvdXIgc2NyaXB0IGZpbGUuIFJlbGF0aXZlIHBhdGhzIGFyZSBlc3BlY2lhbGx5IHVzZWZ1bCBiZWNhdXNlIHRoZXkgd2lsbCB3b3JrIGFjcm9zcyBhbGwgb3BlcmF0aW5nIHN5c3RlbXMgYW5kIHVubGlrZSBhICJoYXJkIHBhdGgiLCBlLmcuIEM6L1VzZXJzL2wtYmFrZXIvcmVwb3MvVGhlX2ZhY3VsdHkvSW50cm9SNEludGxEZXYiLCB0aGlzIHJlbGF0aXZlIHBhdGggd2lsbCB3b3JrIG9uIGFueW9uZSdzIGNvbXB1dGVyLCBub3QganVzdCBteSBvd24hIA0KDQpGb3IgYSAncmVsYXRpdmUgcGF0aCcgdG8gd29yaywgd2UgbmVlZCB0byBnZXQgdG8gdGhlIHJpZ2h0IGRpcmVjdG9yeSAobG9jYXRpb24gd2hlcmUgb3VyIHNjcmlwdCBmaWxlIGlzIHN0b3JlZCkuIFlvdSBjYW4gZG8gdGhpcyB1c2luZyB0aGUgUlN0dWRpbyBtZW51OiANCg0KKiAiU2Vzc2lvbiAtPiBTZXQgV29ya2luZyBEaXJlY3RvcnkgLT4gVG8gU291cmNlIEZpbGUgTG9jYXRpb24iLiBJbiB0aGlzIGNhc2UgdGhpcyB3aWxsIHNldCB0aGUgd29ya2luZyBkaXJlY3RvcnkgdG8gdGhlIGxvY2F0aW9uIHdoZXJlIHRoZSBzY3JpcHQgZmlsZTogIkludHJvUjRJbnRsRGV2LlJtZCIgaXMgc3RvcmVkLiANCg0KKiBBbHRlcm5hdGl2ZWx5LCB5b3UgY2FuIHVzZSBgc2V0d2QoIkM6L1VzZXJzL2wtYmFrZXIvcmVwb3MvVGhlX2ZhY3VsdHkvSW50cm9SNEludGxEZXYiKWAgYW5kIGdpdmUgaXQgdGhlIGZpbGUgcGF0aCB3aGVyZSB5b3VyIHNjcmlwdCBmaWxlIGlzIGxvY2F0ZWQuDQoNCiogVG8gZmluZCBvdXQgd2hlcmUgeW91IGFyZSB5b3UgY2FuIHVzZSB0aGUgZnVuY3Rpb24gYGdldHdkKClgIHdoaWNoIHN0YW5kcyBmb3IgImdldCB3b3JraW5nIGRpcmVjdG9yeSIuDQoNCmBgYHtyIFdvcmtpbmcgZGlyZWN0b3JpZXMsIGV2YWwgPSBGQUxTRX0NCg0KZ2V0d2QoKQ0KDQpgYGANCg0KIyMjIFNwZWNpZnlpbmcgUGF0aHM6IEdvb2QgcHJhY3RpY2UgDQoNCk9uZSBvZiB0aGUgZ29vZCBwcmFjdGljZXMgb2YgY29kaW5nIGlzIHRvIG5ldmVyIHVzZSBhYnNvbHV0ZSBvciAiaGFyZCBwYXRocyIuIEp1c3QgYmVjYXVzZSB5b3VyIHNjcmlwdCB0ZWxscyBhIGNvbGxlYWd1ZSB3aGF0IHN1YmZvbGRlciB0aGUgZGF0YSBpcyBrZXB0IGluIG9uIHlvdXIgY29tcHV0ZXIsIGRvZXMgbm90IGhlbHAgdGhlbSByZXByb2R1Y2UgdGhlIGNvZGUsIGVzcGVjaWFsbHkgYXMgYSBoYXJkIHBhdGggb25seSB3b3JrcyBmb3IgeW91ciBjb21wdXRlci4gDQoNClRoZSBhZHZhbnRhZ2Ugb2YgInJlbGF0aXZlIHBhdGhzIiBpcyB0aGF0IHRoZXkgd2lsbCB3b3JrIGFjcm9zcyBvcGVyYXRpbmcgc3lzdGVtcyBhbmQgYWNyb3NzIGFueW9uZSdzIGNvbXB1dGVyLiBGb3IgZWFjaCBwcm9qZWN0LCBpdCBpcyBiZXN0IHByYWN0aWNlIHRvIHNldCB1cCBhIGZvbGRlciBmb3IgdGhhdCBwcm9qZWN0IHdpdGggeW91ciBzY3JpcHQgZmlsZSBhbmQgc3ViZm9sZGVycyB0byBzdG9yZSB0aGUgImZpZ3VyZXMiIGFuZCB0aGUgImRhdGEiLg0KDQpJbiBzaGFyaW5nIGNvZGUsIHlvdSBzaGFyZSB0aGUgd2hvbGUgbWFzdGVyIGZvbGRlciBjb21wbGV0ZSB3aXRoIHRoZSBmaWd1cmUgYW5kIGRhdGEgc3ViZm9sZGVycy4gVGhlbiBhcyBsb25nIGFzIHRoZXkgc2V0IHRoZSB3b3JraW5nIGRpcmVjdG9yeSB0byB0aGUgbG9jYXRpb24gb2YgeW91ciBzY3JpcHQgZmlsZSwgdGhleSBjYW4gcnVuIHlvdXIgc2NyaXB0IHdpdGggbGl0dGxlIHRyb3VibGUgYWNjZXNzaW5nIHRoZSBmaWd1cmVzIGFuZCBkYXRhIG5lZWRlZCBmcm9tIHRoZSByZWxhdGl2ZSBwYXRocyBzcGVjaWZpZWQuIA0KDQojIyBFeHBsb3JpbmcgdGhlIEdhcG1pbmRlciBEYXRhDQoNCmBgYHtyIFJlYWQgaW4gdGhlIGZpbGUgZ2FwbWluZGVyfQ0KDQpteV9maWxlIDwtIGZpbGUucGF0aCgiZGF0YSIsICJnYXBtaW5kZXIuY3N2IikNCg0KZ2FwbWluZGVyIDwtIHJlYWRfY3N2KGZpbGUgPSBteV9maWxlKQ0KDQpgYGANCg0KDQpUaGUgZGF0YSBjb250YWlucyA4IGNvbHVtbnMNCg0KKiBjb3VudHJ5DQoqIGNvbnRpbmVudA0KKiB5ZWFyDQoqIGxpZmVFeHAuIExpZmUgZXhwZWN0YW5jeSBpbiB5ZWFycy4gDQoqIHBvcC4gQ291bnRyeSBwb3B1bGF0aW9uDQoqIGdkcFBlcmNhcC4gR0RQIHBlciBjYXBpdGEgYWNjb3JkaW5nIHRvIFdvcmxkIEJhbmtkZXYuDQoqIGluZmFudF9tb3J0YWxpdHkuIEluZmFudCBkZWF0aHMgcGVyIDEwMDAuDQoqIGZlcnRpbGl0eS4gQXZlcmFnZSBudW1iZXIgb2YgY2hpbGRyZW4gcGVyIHdvbWFuLg0KDQoNCiMjIyBRdWljayBQb2xsDQoNCkZvciBlYWNoIG9mIHRoZSB0aHJlZSBwYWlycyBvZiBjb3VudHJpZXMgYmVsb3csIHdoaWNoIGNvdW50cnkgZG8geW91IHRoaW5rIGhhZCB0aGUgaGlnaGVzdCBpbmZhbnQgbW9ydGFsaXR5IHJhdGVzIGluIDIwMDc/IFdoaWNoIHBhaXJzIGRvIHlvdSB0aGluayBhcmUgdGhlIG1vc3Qgc2ltaWxhcj8NCg0KMS4gU3JpIExhbmthIG9yIFR1cmtleQ0KDQoyLiBQb2xhbmQgb3IgTWFsYXlzaWENCg0KMy4gUGFraXN0YW4gb3IgVmlldG5hbQ0KDQpXaGljaCBvZiB0aGUgdHdvIHBhaXJzIG9mIGNvdW50cmllcyBkbyB5b3UgdGhpbmsgaGFkIHRoZSBoaWdoZXN0IGxpZmUgZXhwZWN0YW5jeSBpbiAyMDA3LiBXaGljaCBhcmUgdGhlIG1vc3Qgc2ltaWxhcj8NCg0KMS4gU291dGggQWZyaWNhIG9yIFllbWVuDQoNCjIuIENoaWxlIG9yIEh1bmdhcnkNCg0KRm9yIHRoZSB0d28gcGFpcnMgb2YgY291bnRyaWVzIGJlbG93LCB3aGljaCBjb3VudHJ5IGRvIHlvdSB0aGluayBoYWQgdGhlIGhpZ2hlc3QgZ2RwUGVyY2FwIGluIDIwMDc/DQoNCjEuIFN3aXR6ZXJsYW5kIG9yIEt1d2FpdA0KDQoyLiBDb2xvbWJpYSBvciBOZXBhbA0KDQojIyBHZXR0aW5nIHRvIGtub3cgdGhlIGRhdGENCg0KVGhlcmUgYXJlIHNldmVyYWwgdG9vbHMgdG8gZ2V0IHRvIGtub3cgb3VyIGRhdGEuDQoNCiAqIGBWaWV3KClgOiBhbGxvd3MgdXMgdG8gdmlldyB0aGUgZGF0YSBmcmFtZSBhcyBhIHNwcmVhZHNoZWV0Lg0KICogYG5yb3coKWA6IHRlbGxzIHVzIHRoZSBudW1iZXIgb2Ygcm93cyBpbiBvdXIgZGF0YSBmcmFtZS4NCiAqIGBuYW1lcygpYDogZ2l2ZXMgdXMgdGhlIG5hbWVzIG9mIHRoZSBjb2x1bW5zIGluIG91ciBkYXRhIGZyYW1lLg0KICogYGRpbSgpYDogdGVsbHMgdXMgdGhlIGRpbWVuc2lvbnMgb2Ygb3VyIGRhdGEgZnJhbWUuDQogKiBgc3VtbWFyeSgpYDogZ2l2ZSB1cyBzdW1tYXJ5IHN0YXRpc3RpY3MgKGNvdW50cywgbWluLCBtZWRpYW4sIG1lYW4sIG1heCkuIA0KICogYGhlYWQoKWA6IGdpdmVzIHVzIHRoZSBmaXJzdCA2IGVsZW1lbnRzIG9mIHRoZSBkYXRhLg0KICogYHRhaWwoKWA6IGdpdmVzIHVzIHRoZSBsYXN0IDYgZWxlbWVudHMgb2YgdGhlIGRhdGEuDQogKiBgc3RyKClgOiB0ZWxscyB1cyB0aGUgdmFyaWFibGUgdHlwZSAoZS5nLiBGYWN0b3IsIG51bSAobnVtYmVyKSwgaW50IChpbnRlZ2VyKSkuIA0KICogYHVuaXF1ZSgpYDogdGVsbHMgdXMgdGhlIHVuaXF1ZSBlbGVtZW50cyBvZiBhIHZhcmlhYmxlLg0KDQoNCiMjIyBVc2luZyBoZWFkKCkgYW5kIFZpZXcoKQ0KDQpMZXQncyB0YWtlIGEgbG9vayBhdCBgaGVhZGAgYW5kIGBWaWV3YCB0byBpbnNwZWN0IHRoZSBkYXRhIG1vcmUgY2xvc2VseS4gDQoNCmBgYHtyIExvb2sgYXQgdGhlIHRvcCA2IHJvd3MgdXNpbmcgaGVhZCgpfQ0KDQpoZWFkKGdhcG1pbmRlcikNCg0KYGBgDQoNCg0KYGBge3IgTG9vayBhdCB0aGUgZGF0YSB1c2luZyBWaWV3KCksIGV2YWwgPSBGQUxTRX0NCg0KVmlldyhnYXBtaW5kZXIpDQoNCmBgYA0KDQoNCkZyb20gdmlld2luZyB0aGUgZGF0YSB3ZSBjYW4gc2VlIHRoYXQgdGhlIGRhdGEgY29udGFpbnMgZWlnaHQgdmFyaWFibGVzOiBgY291bnRyeWAsIGBjb250aW5lbnRgLCBgeWVhcmAsIGBsaWZlRXhwYCwgYHBvcGAsIGBnZHBQZXJjYXBgLCBgaW5mYW50X21vcnRhbGl0eWAsIGFuZCBgZmVydGlsaXR5YC4NCg0KDQpDbGljayAiRmlsdGVyIiBpbiB0aGUgVmlldyBtZW51LCB5b3UgY2FuIHVzZSB0aGlzIHNpbWlsYXJseSB0byBob3cgeW91IHdvdWxkIGludGVyYWN0IHdpdGggdGhlIGRhdGEgaW4gRXhjZWwuIA0KDQoqKkV4ZXJjaXNlKioNCg0KMS4gVXNpbmcgZmlsdGVyLCB3aGF0IHdhcyB0aGUgbGlmZSBleHBlY3RhbmN5IGluIFJ3YW5kYSBpbiAxOTUyPw0KDQoyLiBXaGljaCBjb3VudHJ5IGhhZCB0aGUgaGlnaGVzdCBpbmZhbnQgbW9ydGFsaXR5IHJhdGU/IFdoYXQgd2FzIHRoZSB5ZWFyPw0KDQoNCiMjIyBDaGVja2luZyB0aGUgc3RydWN0dXJlIG9mIHRoZSBkYXRhIHVzaW5nIHN0cigpDQoNCldlJ3ZlIGFscmVhZHkgdXNlZCBgc3RyKClgIHRvIGV4cGxvcmUgb3VyIHZlY3RvcnMsIHdlIGNhbiBhbHNvIHVzZSBpdCB0byB0YWtlIGEgbG9vayBhdCBvdXIgZGF0YSBmcmFtZSB0byB0ZWxsIHVzIHdoYXQgdHlwZSBvZiB2YXJpYWJsZXMgd2UgaGF2ZS4NCg0KYGBge3IgQ2hlY2sgdGhlIHN0cnVjdHVyZSBvZiB0aGUgZGF0YSB1c2luZyBzdHIoKX0NCg0Kc3RyKGdhcG1pbmRlcikNCg0KYGBgDQoNCkluIHRoaXMgY2FzZSBgY291bnRyeWAgYW5kIGBjb250aW5lbnRgIGFyZSBjaGFyYWN0ZXJzLCBgeWVhcmAsIGBsaWZlRXhwYCwgIGBwb3BgLCBgZ2RwUGVyY2FwYCwgYGluZmFudF9tb3J0YWxpdHlgIGFuZCBgZmVydGlsaXR5YCBhcmUgbnVtYmVycy4NCg0KWW91J2xsIG5vdGljZSBmcm9tIHRoZSBwcmV2aWV3IHRoYXQgYm90aCBgaW5mYW50X21vcnRhbGl0eWAgYW5kIGBmZXJ0aWxpdHlgIGhhdmUgc29tZSBOQXMuIE5BcyBhcmUgY29tbW9ubHkgdXNlZCB0byBzaG93IHRoYXQgdGhlcmUgaXMgbm8gZGF0YSBmb3IgYSBnaXZlbiB5ZWFyIGFuZCB2YXJpYWJsZS4gDQoNCk9uZSBvZiB0aGUgZmlyc3QgdGhpbmdzIHdlIGFyZSBnb2luZyB0byBkbyBpcyBjaGFuZ2UgdGhlIGNvbHVtbnMgYGNvdW50cnlgIGFuZCBgY29udGluZW50YCB0byBmYWN0b3JzLCBhcyB3ZSBjYW4gdHJlYXQgdGhlbSBhcyBjYXRlZ29yaWNhbCB2YXJpYWJsZXMgKGkuZS4gdGhleSBpbmRpY2F0ZSBhIGNhdGVnb3J5IHRoYXQgZGF0YSBiZWxvbmdzIHRvKS4gV2UgY2FuIGRvIHRoaXMgdXNpbmcgdGhlIGBhcy5mYWN0b3JgIGZ1bmN0aW9uLg0KDQpgYGB7ciBDaGFuZ2luZyBnYXBtaW5kZXIgY2hhcmFjdGVycyB0byBmYWN0b3JzfQ0KDQpnYXBtaW5kZXIkY291bnRyeSA8LSBhcy5mYWN0b3IoZ2FwbWluZGVyJGNvdW50cnkpDQpnYXBtaW5kZXIkY29udGluZW50IDwtIGFzLmZhY3RvcihnYXBtaW5kZXIkY29udGluZW50KQ0KDQoNCnN0cihnYXBtaW5kZXIpDQpgYGANCg0KKllvdSdsbCBub3RpY2UgZnJvbSBhYm92ZSB0aGF0IHdlIGNhbiBzZWxlY3QgY29sdW1ucyBieSB1c2luZyB0aGUgZG9sbGFyIHNpZ24gYCRgLg0KDQoNCiMjIyBFeGVyY2lzZXMgDQoNClJ1biB0aGUgZm9sbG93aW5nIGxpbmVzIG9mIGNvZGUgdG8gYW5zd2VyIHRoZSBxdWVzdGlvbnMgYmVsb3cNCg0KMS4gV2hhdCBhcmUgdGhlIGRpbWVuc2lvbnMgb2YgdGhlIGRhdGFmcmFtZT8gV2hhdCBkbyBlYWNoIG9mIHRoZSBudW1iZXJzIHJlZmVyIHRvPw0KDQpgYGB7ciBEYXRhZnJhbWUgRGltZW5zaW9ucywgZXZhbCA9IEZBTFNFfQ0KDQpkaW0oZ2FwbWluZGVyKQ0KDQpgYGANCg0KMi4gV2hhdCBhcmUgdGhlIG5hbWVzIG9mIHRoZSBjb2x1bW5zIGluIHRoZSBkYXRhIGZyYW1lPw0KDQpgYGB7ciBDb2x1bW4gTmFtZXMsIGV2YWwgPSBGQUxTRX0NCg0KbmFtZXMoZ2FwbWluZGVyKQ0KDQpgYGANCg0KKkdpdmVuIHNwZWxsaW5nIGlzIHNvIGltcG9ydGFudCBpbiBSLCBgbmFtZXMoKWAgaXMgYSBoYW5keSB3YXkgdG8gY2hlY2sgdGhlIG5hbWVzIG9mIG91ciBjb2x1bW5zLiANCg0KMy4gV2hhdCBhcmUgdGhlIGZpcnN0IGFuZCBsYXN0IGNvdW50cmllcyBpbiB0aGUgZGF0YSBmcmFtZT8NCg0KYGBge3IgSGVhZCBhbmQgVGFpbCBvZiBEYXRhLCBldmFsID0gRkFMU0V9DQoNCmhlYWQoZ2FwbWluZGVyKQ0KDQp0YWlsKGdhcG1pbmRlcikNCg0KYGBgDQoNCjQuIFdoYXQgaXMgdGhlIG1pbmltdW0gYW5kIG1heGltdW0gZ2RwUGVyY2FwPyBIb3cgbWFueSBOQXMgYXJlIHRoZXJlIGZvciBmZXJ0aWxpdHk/IEhvdyBtYW55IG9ic2VydmF0aW9ucyBkbyB3ZSBoYXZlIGZvciBBZnJpY2E/DQoNCmBgYHtyIERhdGEgU3VtbWFyeSwgZXZhbCA9IEZBTFNFfQ0KDQpzdW1tYXJ5KGdhcG1pbmRlcikNCg0KYGBgDQoNCjUuIFdoYXQgeWVhcnMgYXJlIGNvdmVyZWQgaW4gdGhlIGRhdGEgZnJhbWU/DQoNCmBgYHtyIFVuaXF1ZSB5ZWFycywgZXZhbCA9IEZBTFNFfQ0KDQp1bmlxdWUoZ2FwbWluZGVyJHllYXIpDQoNCmBgYA0KDQo2LiBIb3cgbWFueSBjb3VudHJpZXMgYXJlIGluIG91ciBkYXRhIGZyYW1lPw0KDQpgYGB7ciBVbmlxdWUgY291bnRyaWVzLCBldmFsID0gRkFMU0V9DQoNCnVuaXF1ZShnYXBtaW5kZXIkY291bnRyeSkNCg0KYGBgDQoNCg0KIyMgRXh0cmFjdGluZyBJbmZvcm1hdGlvbiANCg0KKipCYXR0bGVzaGlwKioNCg0KIVtdKHBpY3R1cmVzL2JhdHRsZXNoaXBfZ2FtZS5wbmcpe3dpZHRoPTM1MHB4fQ0KDQoNCldoZW5ldmVyIEkgdGhpbmsgb2YgUiBkYXRhZnJhbWVzIEkgdGhpbmsgb2YgdGhlIGdhbWUgYmF0dGxlc2hpcC4gSW4gYmF0dGxlc2hpcCwgdG8gc3RyaWtlIHRoZSBvdGhlciBvcHBvbmVudCdzIHNoaXBzIHlvdSBsYXVuY2ggbWlzc2lsZXMgYnkgZ2l2aW5nIGEgcm93IGFuZCBjb2x1bW4gcmVmZXJlbmNlIGZvciB0aGUgbG9jYXRpb24gdG8gaGl0IG9uIHlvdXIgb3Bwb25lbnQncyBib2FyZC4NCg0KRGF0YSBmcmFtZXMgYXJlIG11Y2ggdGhlIHNhbWUuIFdlIGNhbiBleHRyYWN0IGFuIGVsZW1lbnQgYnkgc3BlY2lmeWluZyB0aGUgcm93cyBhbmQgdGhlIGNvbHVtbnM6DQoNCiogYGRhdGFfZnJhbWVbcm93cywgY29sdW1uc11gDQoNCiMjIyBTZWxlY3RpbmcgYSBzaW5nbGUgdmFsdWUNCg0KSWYgd2Ugd2FudGVkIHRvIGdldCB0aGUgZmlyc3QgdmFsdWUgZnJvbSB0aGUgZmlyc3Qgcm93IGFuZCBjb2x1bW4gaW4gdGhlIGRhdGFmcmFtZSB3ZSBjb3VsZCB1c2U6DQoNCmBgYHtyIFNlbGVjdCB0aGUgZmlyc3QgZWxlbWVudH0NCg0KZ2FwbWluZGVyWzEsMV0NCg0KYGBgDQoNCiMjIyBTZWxlY3RpbmcgYSB3aG9sZSByb3cNCg0KSWYgd2Ugd2FudGVkIHRoZSB3aG9sZSBmaXJzdCByb3cgd2UgY291bGQgdXNlOg0KDQpgYGB7ciBTZWxlY3QgdGhlIGZpcnN0IHJvd30NCg0KZ2FwbWluZGVyWzEsXQ0KDQpgYGANCg0KTm90aWNlLCB0aGF0IGlmIHdlIHdhbnQgdG8gc2VsZWN0IGFsbCBjb2x1bW5zIHdlIHNpbXBseSBhZGQgYSBjb21tYSBhbmQgbGVhdmUgdGhlIGNvbHVtbiBwb3NpdGlvbiBibGFuay4NCg0KV2hhdCBoYXBwZW5zIGlmIHlvdSBydW4gdGhlIGZvbGxvd2luZz8NCg0KYGBge3IgVGhlIHdyb25nIHdheSB0byBzZWxlY3QgZmlyc3Qgcm93LCBldmFsID0gRkFMU0V9DQoNCmdhcG1pbmRlclsxXQ0KDQpgYGANCg0KIyMjIFNlbGVjdGluZyBzcGVjaWZpYyByb3dzIGFuZCBjb2x1bW5zDQoNCklmIHdlIHdhbnRlZCB0aGUgZmlyc3QgNSByb3dzIGFuZCB0aGUgZmlyc3QgYW5kIHRoaXJkIGNvbHVtbnMgd2UgY291bGQgdXNlOg0KDQpgYGB7ciBTZWxlY3QgdGhlIGZpcnN0IDUgcm93cyBhbmQgZmlyc3QgYW5kIHRoaXJkIGNvbHVtbnN9DQoNCmdhcG1pbmRlclsxOjUsIGMoMSwzKV0NCg0KYGBgDQoNClJlbWVtYmVyIGZyb20gYmVmb3JlIHRoYXQgaWYgd2UgaGF2ZSBub25jb25zZWN1dGl2ZSBwb3NpdGlvbnMsIHdlIG5lZWQgdG8gdXNlIHRoZSBgYygpYCBmdW5jdGlvbiB0byAqKmMqKm9tYmluZSB0aGVzZSBwb3NpdGlvbnMgaW50byBhIGxpc3QuIA0KDQojIyMgUmVmZXJlbmNlIGNvbHVtbnMgYnkgbmFtZQ0KDQpXZSBjYW4gYWxzbyByZWZlcmVuY2UgdGhlIGNvbHVtbiBieSBuYW1lOg0KDQpgYGB7ciBSZWZlcmVuY2luZyB0aGUgY29sdW1uIGJ5IGNvbHVtbiBuYW1lfQ0KDQpnYXBtaW5kZXJbMTo1LCBjKCJjb3VudHJ5IiwgImdkcFBlcmNhcCIpXQ0KDQpgYGANCg0KV2h5IG1pZ2h0IHRoaXMgYmUgcHJlZmVycmVkIHRvIHJlZmVyZW5jaW5nIGNvbHVtbnMgYnkgbnVtYmVyPw0KDQojIyMgRXhlcmNpc2VzDQoNCg0KMS4gRXh0cmFjdCBhbGwgcm93cyBmcm9tIHRoZSBjb2x1bW4gYHBvcGAgYW5kIHNhdmUgaXQgaW4gYSBuZXcgb2JqZWN0IGNhbGxlZCBgcG9wYA0KDQpIaW50OiBsb29rIGJhY2sgdG8gaG93IHdlIHNlbGVjdGVkIHJvdyAxIGFuZCBhbGwgY29sdW1ucy4gDQoNCmBgYHtyIFNlbGVjdCB0aGUgY29sdW1uIHBvcCwgZXZhbCA9IEZBTFNFfQ0KDQpwb3AgPC0gZ2FwbWluZGVyW10NCg0KYGBgDQoNCjIuIEV4dHJhY3QgdGhlIDV0aCByb3cgYW5kIDZ0aCBjb2x1bW4gZnJvbSB0aGUgZGF0YXNldA0KDQpgYGB7ciBFeHRyYWN0IDV0aCByb3cgYW5kIDZ0aCBjb2x1bW4sIGV2YWwgPSBGQUxTRX0NCg0KZ2FwbWluZGVyW10NCg0KYGBgDQoNCioqQm9udXMqKg0KDQozLiBFeHRyYWN0IGFsbCB0aGUgcm93cyBmb3IgdGhlIGNvbHVtbnMgYGdkcFBlcmNhcGAgYW5kIGBwb3BgLg0KDQpIaW50OiBsb29rIGJhY2sgdG8gaG93IHdlIHNlbGVjdGVkIHJvdyAxIGFuZCBhbGwgY29sdW1ucy4gDQoNCg0KYGBge3IgU2VsZWN0IGNvbHVtbnMgZ2RwUGVyY2FwIGFuZCBwb3AsIGV2YWwgPSBGQUxTRX0NCg0KZ2FwbWluZGVyW10NCg0KYGBgDQoNCjQuIEV4dHJhY3Qgcm93cyA1LCAyMCwgYW5kIDQ0IGZyb20gdGhlIGNvbHVtbiBgbGlmZUV4cGAgYW5kIHNhdmUgaXQgaW4gYSBuZXcgZGF0YSBmcmFtZSBjYWxsZWQgYHN1Yl9saWZlRXhwYA0KDQpgYGB7ciBFeHRyYWN0IHJvd3MgNSBhbmQgMjAgYW5kIDQ0IGZyb20gY29sIGxpZmVFeHAsIGV2YWwgPSBGQUxTRX0NCg0KIDwtIGdhcG1pbmRlcltdDQoNCmBgYA0KDQoNCiMjIERhdGEgc3Vic2V0dGluZyBhbmQgc3VtbWFyaXNpbmcgdXNpbmcgYGRwbHlyYDoNCg0KU28gZmFyIEkndmUgc2hvd24geW91IHRoZSAnb2xkIHNjaG9vbCcgbWV0aG9kIGZvciBleHRyYWN0aW5nIGFuZCBmaWx0ZXJpbmcgZGF0YS4gSXQgaXMgdXNlZnVsIHRvIGtub3cgdGhlIGxheW91dCBvZiB2ZWN0b3JzIGFuZCBkYXRhZnJhbWVzLCBlc3BlY2lhbGx5IGlmIHlvdSBlbmQgdXAgd3JpdGluZyB5b3VyIG93biBgZm9yIGxvb3BzYCBvciBmdW5jdGlvbnMgaW4gdGhlIGZ1dHVyZS4gDQoNCkhvd2V2ZXIsIHRoZSBwYWNrYWdlLCBgZHBseXJgLCBoYXMgbWFkZSBhIGxvdCBvZiBkYXRhIG1hbmlwdWxhdGlvbiBlYXNpZXIgYW5kIGNsZWFyZXIgdXNpbmcgKip2ZXJicyoqIHRvIGZpbHRlciBhbmQgc2VsZWN0IGRpZmZlcmVudCBlbGVtZW50cy4NCg0KICAqIGBzZWxlY3QoKWAgc3Vic2V0cyBjb2x1bW5zIGJhc2VkIG9uIHRoZWlyIG5hbWVzLg0KICAqIGBmaWx0ZXIoKWAgc3Vic2V0cyByb3dzIGJhc2VkIG9uIHRoZWlyIHZhbHVlcy4NCiAgKiBgc3VtbWFyaXNlKClgIGNhbGN1bGF0ZXMgc3VtbWFyeSBzdGF0aXN0aWNzLg0KICAqIGBncm91cF9ieSgpYCBncm91cHMgdmFyaWFibGUgZm9yIHN1bW1hcmlzaW5nLg0KICAqIGBtdXRhdGUoKWAgYWRkcyBuZXcgY29sdW1ucyB0aGF0IGFyZSBmdW5jdGlvbnMgb2YgZXhpc3RpbmcgdmFyaWFibGVzLiANCg0KVGhlc2UgdmVyYnMgY2FuIGJlIGNvbWJpbmVkIGluIHBvd2VyZnVsIHdheXMgdG8gZG8gc29tZSByZWFsbHkgaW50ZXJlc3RpbmcgZGF0YSBtYW5pcHVsYXRpb24gdGFza3MuIA0KDQojIyMgc2VsZWN0DQoNCmBgYHtyIFNlbGVjdCBjb2x1bW5zIGxpZmVFeHAgYW5kIHBvcCB1c2luZyBzZWxlY3QoKX0NCg0Kc2VsZWN0KGdhcG1pbmRlciwgbGlmZUV4cCwgcG9wKQ0KDQpgYGANCg0KIyMjIyBUaGUgcGlwZSBvcGVyYXRvcg0KDQpUaGVzZSB2ZXJicyBjYW4gYmUgdXNlZCBieSBzcGVjaWZ5aW5nIHRoZSBkYXRhIGZyYW1lIGZpcnN0LCBvciB1c2luZyB0aGUgcGlwZSBvcGVyYXRvciBgJT4lYC4gWW91IGNhbiB0aGluayBvZiB0aGUgdGhlIHBpcGUgb3BlcmF0b3IgYXMgbWVhbmluZyAqKiJhbmQgdGhlbiIqKi4gDQoNCmBgYHtyIFNlbGVjdCB0aGUgY29sdW1ucyBsaWZlRXhwIGFuZCBjb3VudHJ5IHVzaW5nIHNlbGVjdCgpfQ0KDQpnYXBtaW5kZXIgJT4lDQogIHNlbGVjdChsaWZlRXhwLCBjb3VudHJ5KQ0KDQpgYGANCg0KT25lIGJpZyBhZHZhbnRhZ2Ugb2YgdGhlIHBpcGUgb3BlcmF0b3IgaXMgdGhhdCBpdCBkb2VzIG5vdCBjaGFuZ2UgeW91ciByYXcgZGF0YSBpbiBhbnkgd2F5IQ0KDQpgYGB7ciBUaGUgcGlwZSBvcGVyYXRvciBkb2VzIG5vdCBjaGFuZ2UgdGhlIGRhdGF9DQoNCmhlYWQoZ2FwbWluZGVyKQ0KDQpgYGANCg0KVGhpcyBpcyByZWFsbHkgdXNlZnVsIGJlY2F1c2UgaXQgbWVhbnMgeW91IGNhbiBtYW5pcHVsYXRlIHlvdXIgZGF0YSB3aXRob3V0IGhhdmluZyB0byBzdG9yZSBuZXcgZGF0YSBmcmFtZXMgZm9yIGVhY2ggc3RlcC4gSXQgYWxzbyBtZWFucyB5b3UgbmV2ZXIgY29tcHJpbWlzZSB0aGUgb3JpZ2luYWwgZGF0YS4gDQoNCiMjIyMgQXNzaWduIHlvdXIgb3V0cHV0IHRvIGEgbmV3IGRhdGEgZnJhbWUNCg0KWW91IGNhbiBhbHNvIGFzc2lnbiB5b3VyIG91dHB1dCB0byBhIG5ldyBkYXRhIGZyYW1lLg0KDQpgYGB7ciBDcmVhdGUgYSBuZXcgZGF0YSBmcmFtZSBsaWZlRXhwX2J5X2NvdW50cnkgd2l0aCB0aGUgY29sdW1ucyBsaWZlRXhwIGFuZCBjb3VudHJ5fQ0KDQpsaWZlRXhwX2J5X2NvdW50cnkgPC0gZ2FwbWluZGVyICU+JQ0KICBzZWxlY3QobGlmZUV4cCwgY291bnRyeSkNCg0KaGVhZChsaWZlRXhwX2J5X2NvdW50cnkpDQoNCmBgYA0KDQojIyMgKipFeGVyY2lzZXMqKg0KDQoxLiBSdW4gdGhlIGZvbGxvd2luZyBsaW5lIG9mIGNvZGUsIHdoYXQgZG9lcyB0aGUgbWludXMgZG8/DQoNCg0KYGBge3IgVXNpbmcgLSB0byByZW1vdmUgY29sdW1ucywgZXZhbCA9IEZBTFNFfQ0KDQpnYXBtaW5kZXIgJT4lDQogIHNlbGVjdCgtYyhsaWZlRXhwLCBjb3VudHJ5KSkNCg0KYGBgDQoNCjIuIFNlbGVjdCB0aGUgY29sdW1ucyBgY291bnRyeWAsIGBjb250aW5lbnRgIGFuZCBgZ2RwUGVyY2FwYCBmcm9tIHRoZSBkYXRhIGZyYW1lLiANCg0KYGBge3IgU2VsZWN0IHRoZSBjb2x1bW5zIGNvdW50cnksIGNvbnRpbmVudCBhbmQgZ2RwUGVyY2FwIHVzaW5nIHNlbGVjdCwgZXZhbCA9IEZBTFNFfQ0KDQpnYXBtaW5kZXIgJT4lDQoNCg0KYGBgDQoNCioqRXh0cmEgQ3JlZGl0KioNCg0KMy4gV3JpdGUgY29kZSBmb3IgdHdvIHdheXMgeW91IGNhbiBzZWxlY3QgYWxsIHRoZSBjb2x1bW5zIGV4Y2VwdCBmb3IgeWVhci4NCg0KYGBge3IgV3JpdGUgY29kZSBmb3IgdHdvIHdheXMgdG8gc2VsZWN0IGFsbCBjb2x1bW5zIGJ1dCB5ZWFyLCBldmFsID0gRkFMU0V9DQoNCmdhcG1pbmRlciAlPiUNCg0KDQpgYGANCg0KIyMjIGZpbHRlcg0KDQoqIGBmaWx0ZXJgOiBzdWJzZXR0aW5nIHJvd3MNCg0KRm9yIGZpbHRlcmluZyBpdCBpcyB1c2VmdWwgdG8ga25vdyB5b3VyIHNldCBvZiBvcGVyYXRvcnM6DQoNCkxvZ2ljYWwgT3BlcmF0b3J8IERlc2NyaXB0aW9uDQo6LS0tLS0tLS0tLS0tLS06fDotLS0tLS0tLS0tLS06DQogICAgICAgIDwgICAgICAgfCBMZXNzIFRoYW4NCiAgICAgICA8PSAgICAgICB8IExlc3MgVGhhbiBvciBFcXVhbCBUbw0KICAgICAgIFw+ICAgICAgIHwgR3JlYXRlciBUaGFuDQogICAgICAgPj0gICAgICAgfCBHcmVhdGVyIFRoYW4gb3IgRXF1YWwgVG8NCiAgICAgICA9PSAgICAgICB8IEVxdWFsIFRvDQogICAgICAgIT0gICAgICAgfCBOb3QgRXF1YWwgVG8NCiAgICAgICBcfCAgICAgICB8IE9yDQogICAgICAgICYgICAgICAgfCBBbmQNCiAgJWluJSBjKC4uLi4pICB8IE1lbWJlcnNoaXAgKipvbmUgaW4qKiBhIGxpc3Qgb2YgZWxlbWVudHMNCg0KKElnbm9yZSBiYWNrc2xhc2hlcyBpbiB0aGUgbm90ZWJvb2suKQ0KDQpXZSBjYW4gdXNlIGZpbHRlciB0byBwaWNrIG91dCBhIHBhcnRpY3VsYXIgY291bnRyeS4gTi5CLiwgaWYgd2UgYXJlIHVuc3VyZSBvZiBuYW1lcyB3ZSBjYW4gYWx3YXlzIHVzZSBgdW5pcXVlKGdhcG1pbmRlciRjb3VudHJ5KWAgdG8gY2hlY2sgc3BlbGxpbmdzLg0KDQojIyMjIEZpbHRlciB1c2luZyBgPT1gDQoNCmBgYHtyIFVzZSBmaWx0ZXIgdG8gcGljayBvdXQgYSBwYXJ0aWN1bGFyIGNvdW50cnl9DQoNCmdhcG1pbmRlciAlPiUNCiAgZmlsdGVyKGNvdW50cnkgPT0gIlllbWVuLCBSZXAuIikNCg0KYGBgDQoNCiMjIyMgRmlsdGVyIHJvd3MgZnJvbSBhIHNldCBvZiBtYXRjaGVzDQoNCldlIGNhbiBhbHNvIHVzZSBmaWx0ZXIgdG8gZmlsdGVyIHJvd3MgZnJvbSBhIHNldCBvZiBjb3VudHJpZXMgb2YgaW50ZXJlc3QNCg0KYGBge3IgVXNlIGZpbHRlciB0byBmaWx0ZXIgcm93IGZyb20gYSBzZXQgb2YgY291bnRyaWVzfQ0KDQpnYXBtaW5kZXIgJT4lDQogIGZpbHRlcihjb3VudHJ5ICVpbiUgYygiTW9yb2NjbyIsICJBbGdlcmlhIiwgIkxpYnlhIiwgIlR1bmlzaWEiLCAiRWd5cHQiLCAiU3VkYW4iLCAiSm9yZGFuIiwgIk9tYW4iLCAiTGViYW5vbiIsICJJc3JhZWwiLCAiU3lyaWEiLCAiWWVtZW4sIFJlcC4iKSkNCg0KYGBgDQoNCiMjIyMgQ29tYmluaW5nIG11bHRpcGxlIGZpbHRlcnMNCg0KWW91IGNhbiBhZGQgbXVsdGlwbGUgZmlsdGVycyB3aXRoIGEgY29tbWEuDQoNCmBgYHtyIEFkZCBtdWx0aXBsZSBmaWx0ZXJzIHdpdGggYSBjb21tYX0NCg0KZ2FwbWluZGVyICU+JQ0KICBmaWx0ZXIoY291bnRyeSA9PSAiWWVtZW4sIFJlcC4iLCB5ZWFyID49IDE5NjAgJiB5ZWFyIDw9IDE5ODUpDQoNCmBgYA0KDQoNCiMjIyAqKkV4ZXJjaXNlcyoqDQoNCjEuIFdoYXQgZG8gdGhlc2UgbGluZXMgb2YgY29kZSBmaWx0ZXIgdGhlIGRhdGEgZm9yPw0KDQpgYGB7ciBXaGF0IGRvZXMgdGhpcyBjb2RlIGZpbHRlciBmb3IsIGV2YWwgPSBGQUxTRX0NCg0KZ2FwbWluZGVyICU+JQ0KICBmaWx0ZXIoY29udGluZW50ID09ICJFdXJvcGUiLCBsaWZlRXhwID4gNzApDQoNCmBgYA0KDQoNCjIuIEZpbHRlciB0aGUgZGF0YSBzbyB0aGF0IHlvdSBvbmx5IGdldCBlbnRyaWVzIGZvciBjb3VudHJpZXMgaW4gIkFzaWEiIHdoZXJlIHRoZSAibGlmZUV4cCIgd2FzIGJlbG93IDM1ICANCg0KYGBge3IgRmlsdGVyIHRoZSBkYXRhIGZvciBjb3VudHJpZXMgaW4gQXNpYSB3aGVyZSBsaWZlRXhwIGlzIGxlc3MgdGhhbiAzNSwgZXZhbCA9IEZBTFNFfQ0KDQpnYXBtaW5kZXIgJT4lDQogIA0KYGBgDQoNCjMuIEZpbHRlciB0aGUgZGF0YSBzbyB0aGF0IHlvdSBvbmx5IGdldCBlbnRyaWVzIHdoZXJlIHRoZSBnZHBQZXJjYXAgd2FzIGVxdWFsIHRvIDEwMDAgb3IgbGVzcy4gDQoNCmBgYHtyIEZpbHRlciB0aGUgZGF0YSBzbyB0aGF0IHlvdSBvbmx5IGdldCBlbnRyaWVzIHdoZXJlIGdkcFBlcmNhcCBpcyBlcXVhbCB0byAxMDAwIG9yIGxlc3MsIGV2YWwgPSBGQUxTRX0NCg0KZ2FwbWluZGVyICU+JQ0KICANCmBgYA0KDQoqKkV4dHJhIENyZWRpdCoqDQoNCjQuIEZpbHRlciB0aGUgZGF0YSB1c2luZyBgJWluJWAgdG8gZ2V0IHRoZSBjb3VudHJpZXMgIkNoaWxlIiwgIkFyZ2VudGluYSIsICJVcnVndWF5IiwgYW5kICJQZXJ1IiBhbmQgb25seSB5ZWFycyBncmVhdGVyIHRoYW4gb3IgZXF1YWwgdG8gMTk5Mi4gDQoNCmBgYHtyIEZpbHRlciB0aGUgZGF0YSBmb3IgQ2hpbGUgQXJnZW50aW5hIFVydWd1YXkgYW5kIFBlcnUgZm9yIHllYXJzIGdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0byAxOTkyLCBldmFsID0gRkFMU0V9DQoNCmdhcG1pbmRlciAlPiUNCg0KDQpgYGANCg0KNS4gRmlsdGVyIHRoZSBkYXRhIHVzaW5nIGAhPWAgdG8gaW5jbHVkZSB0aGUgZGF0YSBmcm9tIGFsbCBjb250aW5lbnRzIGFwYXJ0IGZyb20gRXVyb3BlLiANCg0KYGBge3IgRmlsdGVyIHRoZSBkYXRhIHRvIGluY2x1ZSBkYXRhIGZyb20gYWxsIGNvbnRpbmVudHMgYXBhcnQgZnJvbSBFdXJvcGUsIGV2YWwgPSBGQUxTRX0NCg0KZ2FwbWluZGVyICU+JQ0KDQpgYGANCg0KIyMjIHN1bW1hcmlzZSgpDQoNCiogYHN1bW1hcmlzZSgpYCB1c2VzIGV4aXN0aW5nIFIgZnVuY3Rpb25zIHRvIGNhbGN1bGF0ZSBzdW1tYXJ5IHN0YXRpc3RpY3MuIA0KDQojIyMjIENhbGN1bGF0ZSBhIHN1bW1hcnkgc3RhdGlzdGljIHVzaW5nIGBzdW1tYXJpc2UoKWANCg0KRm9yIGluc3RhbmNlIHdlIG1heSB3aXNoIHRvIGNhbGN1bGF0ZSB0aGUgbWVhbiBsaWZlRXhwIGZvciBhbGwgY291bnRyaWVzOg0KDQpgYGB7ciBDYWxjdWxhdGUgdGhlIG1lYW5fbGlmZUV4cCB1c2luZyBzdW1tYXJpc2V9DQoNCihsaWZlRXhwX3N0YXRzIDwtIGdhcG1pbmRlciAlPiUNCiAgICAgICAgICAgICAgICAgIHN1bW1hcmlzZShtZWFuX2xpZmVFeHAgPSBtZWFuKGxpZmVFeHApKSkNCg0KYGBgDQoNCiMjIyMgQ2FsY3VsYXRlIG11bHRpcGxlIHN1bW1hcnkgc3RhdGlzdGljcw0KDQpXZSBjYW4gYWxzbyBjYWxjdWxhdGUgbXVsdGlwbGUgc3VtbWFyeSBzdGF0aXN0aWNzIGF0IHRoZSBzYW1lIHRpbWUsIHNlcGFyYXRpbmcgZWFjaCBuZXcgc3VtbWFyeSB2YXJpYWJsZSB3aXRoIGEgYCxgLiBUaGlzIHdheSB3ZSBjYW4gY2FsY3VsYXRlIHRoZSBtZWFuLCBtaW4sIGFuZCBtYXggbGlmZUV4cCBmb3IgYWxsIGNvdW50cmllcyBjb21iaW5lZDoNCg0KYGBge3IgVXNlIHN1bW1hcmlzZSB0byBjYWxjdWxhdGUgbWVhbl9saWZlRXhwLCBtaW5fbGlmZUV4cCwgYW5kIG1heF9saWZlRXhwfQ0KDQoobGlmZUV4cF9zdGF0cyA8LSBnYXBtaW5kZXIgJT4lDQogICAgICAgICAgICAgICAgICBzdW1tYXJpc2UoDQogICAgICAgICAgICAgICAgICAgIG1lYW5fbGlmZUV4cCA9IG1lYW4obGlmZUV4cCksICMgbWVhbg0KICAgICAgICAgICAgICAgICAgICBtaW5fbGlmZUV4cCA9IG1pbihsaWZlRXhwKSwgIyBtaW4NCiAgICAgICAgICAgICAgICAgICAgbWF4X2xpZmVFeHAgPSBtYXgobGlmZUV4cCkpICMgbWF4DQogICAgICAgICAgICAgICAgICAgICkgDQoNCg0KYGBgDQoNCiMjIyBncm91cF9ieSgpDQoNCiogYGdyb3VwX2J5KClgIHVzZWQgdG8gZ3JvdXAgdmFyaWFibGVzLiBDYW4gYmUgZXNwZWNpYWxseSB1c2VmdWwgYmVmb3JlIHN1bW1hcmlzaW5nLg0KDQoNCmBgYHtyIFVzZSBncm91cF9ieSB0byBncm91cCBieSBjb3VudHJ5IGFuZCB0aGVuIHN1bW1hcmlzZX0NCg0KKGxpZmVFeHBfc3RhdHNfY291bnRyeSA8LSBnYXBtaW5kZXIgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwX2J5KGNvdW50cnkpICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdW1tYXJpc2UoDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1lYW5fbGlmZUV4cCA9IG1lYW4obGlmZUV4cCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pbl9saWZlRXhwID0gbWluKGxpZmVFeHApLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF4X2xpZmVFeHAgPSBtYXgobGlmZUV4cCkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSkgDQoNCmBgYA0KDQojIyMgKipFeGVyY2lzZXM6KioNCg0KMS4gV2hhdCBkb2VzIHRoZSBmb2xsb3dpbmcgYml0IG9mIGNvZGUgZG8/IA0KDQpgYGB7ciBXaGF0IGRvZXMgdGhlIGZvbGxvd2luZyBncm91cF9ieSBzdW1tYXJpc2UgY29kZSBkbywgZXZhbCA9IEZBTFNFfQ0KDQpnYXBtaW5kZXIgJT4lDQogICAgICBncm91cF9ieShjb250aW5lbnQsIHllYXIpICU+JQ0KICAgICAgc3VtbWFyaXNlKG1lYW5fZ2RwUGVyY2FwID0gbWVhbihnZHBQZXJjYXApKQ0KDQoNCmBgYA0KDQoyLiBHcm91cCB0aGUgZGF0YSBieSBjb3VudHJ5IGFuZCBjcmVhdGUgdHdvIG5ldyB2YXJpYWJsZXMgd2hpY2ggc3VtbWFyaXNlIHRoZSBtaW5pbXVtIGFuZCBtYXhpbXVtIHBvcHVsYXRpb24gc2l6ZXMuIA0KDQoNCmBgYHtyIEdyb3VwIHRoZSBkYXRhIGJ5IGNvdW50cnkgYW5kIGNyZWF0ZSB0d28gbmV3IHZhcmlhYmxlcyB3aGljaCBzdW1tYXJpc2UgdGhlIG1pbmltdW0gYW5kIG1heGltdW0gcG9wLCBldmFsID0gRkFMU0V9DQoNCmdhcG1pbmRlciAlPiUNCiAgICAgICAgICANCmBgYA0KDQoqKkJvbnVzKioNCg0KMy4gR3JvdXAgdGhlIGRhdGEgYnkgY29udGluZW50IGFuZCB5ZWFyLiBTdW1tYXJpc2UgdGhlIG1heGltdW0gYW5kIG1pbmltdW0gcG9wdWxhdGlvbi4NCg0KYGBge3IgU3VtbWFyaXNlIG1heGltdW0gYW5kIE1pbmltdW0gcG9wdWxhdGlvbiBieSBjb250aW5lbnQgYW5kIHllYXIsIGV2YWwgPSBGQUxTRX0NCg0KZ2FwbWluZGVyICU+JQ0KICAgICAgICAgIA0KYGBgDQoNCg0KIyMjIFRoZSBwaXBlIGZ1bmN0aW9uICU+JQ0KDQohW10ocGljdHVyZXMvYXNzZW1ibHlfbGluZS5qcGcpe3dpZHRoPTM1MHB4fQ0KDQoNCldlJ3ZlIHNlZW4gYW4gZXhhbXBsZSBvZiB0aGUgcGlwZSBmdW5jdGlvbiBgJT4lYCBpbiB0aGUgYGdyb3VwX2J5KClgIGV4YW1wbGUgYWJvdmUuIFRoZSBwaXBlIGZ1bmN0aW9uIGFsbG93cyB5b3UgdG8gY29tYmluZSBtdWx0aXBsZSBkYXRhIHdyYW5nbGluZyBzdGVwcyB3aGljaCB3aWxsIGJlIGNhcnJpZWQgb3V0IGluIG9yZGVyLiANCg0KSSBsaWtlIHRvIHRoaW5rIG9mIHRoZSBwaXBlIGZ1bmN0aW9uIGFzIHRoZSBzZXBhcmF0b3Igb2YgZGlmZmVyZW50IGpvYnMgb24gYW4gYXNzZW1ibHkgbGluZS4gDQoNCg0KIVtdKHBpY3R1cmVzL2Fzc2VtYmx5X2xpbmVfYmlyZF9ob3VzZS5wbmcpe3dpZHRoPTY1MHB4fQ0KDQoqIFRyZWUgKHJhdyBkYXRhKSAtPiBQbGFua3MgKGdyb3VwZWQgZGF0YSkgLT4gQmlyZCBIb3VzZSAoc3VtbWFyaXNlZCBkYXRhKQ0KDQpZb3UgYmVnaW4gd2l0aCB5b3VyIHJhdyBkYXRhIChlLmcuIHRyZWUpLCBpdCB0aGVuIGdvZXMgdGhyb3VnaCB0aGUgcGlwZSB0byB0aGUgbmV4dCBzdGF0aW9uIHdoZXJlIGl0IGlzIG1vZGlmaWVkIGluIHNvbWUgd2F5IChlLmcuIGN1dCBpbnRvIHBsYW5rcyksIGl0IGNhbiB0aGVuIHBhc3MgdG8gYW5vdGhlciBzdGF0aW9uIHdoZXJlIGl0IGNhbiBiZSBmdXJ0aGVyIG1vZGlmaWVkLCBhbmQgc28gb24gYW5kIHNvIGZvcnRoLCB1bnRpbCBWb2lsYSEgeW91IGhhdmUgeW91ciBmaW5hbCBwcm9kdWN0IChlLmcuIGEgYmlyZCBob3VzZSkuDQoNCkxldCdzIHNheSB3ZSBhcmUgaW50ZXJlc3RlZCBpbiBjYWxjdWxhdGluZyB0aGUgbGlmZSBleHBlY3RhbmN5IGluIFllbWVuIHByZSAxOTgwLiBXZSBjYW4gcnVuIHRoZSBmb2xsb3dpbmc6DQoNCmBgYHtyIFllbWVuIExpZmUgRXhwZWN0YW5jeSBwcmUgMTk4MH0NCg0KDQp5ZW1lbl9wcmUxOTgwX21lYW5fbGlmZUV4cCA8LSBnYXBtaW5kZXIgJT4lDQogIGZpbHRlcihjb3VudHJ5ID09ICJZZW1lbiwgUmVwLiIsIHllYXIgPDE5ODApICU+JSAjIFJldHVybiBkYXRhIGZvciBZZW1lbiBwcmUgMTk4MA0KICBzZWxlY3QobGlmZUV4cCkgJT4lICMgU2VsZWN0IHRoZSBjb2x1bW4gbGlmZUV4cCAobGlmZSBleHBlY3RhbmN5KQ0KICBzdW1tYXJpc2UobWVhbmxpZmVFeHAgPSBtZWFuKGxpZmVFeHApKSAjIENhbGN1bGF0ZSBtZWFuIGxpZmUgZXhwZWN0YW5jeQ0KDQpgYGANCg0KDQpXZSBjYW4gYWxzbyBjb21iaW5lIG11bHRpcGxlIG9wZXJhdG9ycyBhbmQgbG9vayBhdCBhIHNsaWNlIG9mIHRoZSBkYXRhLg0KDQpgc2xpY2UoKWAgY2hvb3NlcyByb3dzIGJ5IHRoZWlyIHBvc2l0aW9uIHdpdGhpbiB0aGUgZ3JvdXAuIEluIHRoaXMgY2FzZSB3ZSBhcmUgc2VsZWN0aW5nIG91dCB0aGUgbWluaW11bSBsaWZlIEV4cGVjdGFuY3kuDQoNCmBgYHtyIFVzaW5nIGdyb3VwX2J5IGFuZCBzbGljZTogbWluIGxpZmVFeHB9DQoNCmdhcG1pbmRlciAlPiUNCiAgZ3JvdXBfYnkoeWVhcikgJT4lDQogIHNsaWNlKHdoaWNoLm1pbihsaWZlRXhwKSkNCg0KYGBgDQoNCldlIGNhbiBhbHNvIHNlZSB3aGljaCBjb3VudHJ5IGhhZCB0aGUgaGlnaGVzdCBsaWZlIEV4cGVjdGFuY3kgaW4gZWFjaCB5ZWFyLiANCg0KYGBge3IgVXNpbmcgZ3JvdXBfYnkgYW5kIHNsaWNlOiBtYXggbGlmZUV4cH0NCg0KZ2FwbWluZGVyICU+JQ0KICBncm91cF9ieSh5ZWFyKSAlPiUNCiAgc2xpY2Uod2hpY2gubWF4KGxpZmVFeHApKQ0KDQpgYGANCg0KDQojIyMgTXV0YXRlDQoNCiAgKiBgbXV0YXRlKClgIGFkZHMgbmV3IGNvbHVtbnMgdGhhdCBhcmUgZnVuY3Rpb25zIG9mIGV4aXN0aW5nIHZhcmlhYmxlcy4gDQoNClVzaW5nIHRoZSB2ZXJiIGBtdXRhdGUoKWAgd2UgY2FuIGNyZWF0ZSBhIG5ldyBkYXRhIGNvbHVtbiBjYWxsZWQgZ2RwLiBJbiB0aGlzIGNhc2UgdGhlIHBlciBjYXBpdGEgR0RQIGBnZHBQZXJjYXBgIG5lZWRzIHRvIGJlIG11bHRpcGxpZWQgYnkgdGhlIHBvcHVsYXRpb24gYHBvcGAgdG8gZ2V0IHRoZSBvdmVyYWxsIEdEUC4NCg0KYGBge3IgQ3JlYXRpbmcgYSBuZXcgdmFyaWFibGUgZ2RwfQ0KDQooZ2FwbWluZGVyPC0gZ2FwbWluZGVyICU+JQ0KICBtdXRhdGUoZ2RwID0gZ2RwUGVyY2FwKnBvcCkpDQoNCmBgYA0KDQpUaGlzIGlzIHVzZWZ1bCBpZiB3ZSB3YW50IHRvIGxvb2sgYXQgdGhlIG92ZXJhbGwgZ2RwLCBidXQgaXQgaXMgYWxzbyBhIGh1Z2UgbnVtYmVyIHdoaWNoIGlzIGRpZmZpY3VsdCB0byBjb21wYXJlIGFtb25nIGNvdW50cmllcyBpbiBhIG1lYW5pbmdmdWwgd2F5Lg0KDQojIyBKb2luaW5nIGRhdGEgZnJhbWVzOiB3aGVuIG9uZSBkYXRhIGZyYW1lIGlzIG5vdCBlbm91Z2gNCg0KSXQgaXMgb2Z0ZW4gdGhlIGNhc2UgdGhhdCBvdXIgZGF0YSBpcyBzcHJlYWQgb3V0IG92ZXIgc2V2ZXJhbCBkYXRhIGZyYW1lcyB0aGF0IHdlIGFyZSBpbnRlcmVzdGVkIGluIGNvbWJpbmluZy4gV2UgY2FuICoqam9pbioqIHRoZXNlIGRhdGEgZnJhbWVzIHRvZ2V0aGVyIHVzaW5nIGEgdmFyaWV0eSBvZiBgam9pbmAgZnVuY3Rpb25zIGZyb20gdGhlIGBkcGx5cmAgcGFja2FnZS4NCg0KIVtdKHBpY3R1cmVzL2V4cGxhaW5pbmdfam9pbnMuanBnKXt3aWR0aD0zNTBweH0NCg0KTGV0J3Mgd2FsayB0aHJvdWdoIHRoZSBkaWZmZXJlbnQgdHlwZXMgb2Ygam9pbnMgdXNpbmcgYSBzaW1wbGUgZXhhbXBsZS4gDQoNCkxldCdzIHNheSB3ZSBoYXZlIHR3byBkYXRhIGZyYW1lcyBvZiAidGFibGVzIiB3ZSBhcmUgaW50ZXJlc3RpbmcgaW4gam9pbmluZyB0b2dldGhlcjogYHBlcnNvbl90YWJsZWAsIHdoaWNoIGNvbnRhaW5zIHRoZSBpbmZvcm1hdGlvbiBhYm91dCB0aGUgZW1wbG95ZWUgKGBQZXJzb25fSURgLCBgTmFtZWAgYW5kIGBKb2JfSURgKSBhbmQgdGhlIGBqb2JfdGFibGVgLCB3aGljaCBjb250YWlucyBpbmZvcm1hdGlvbiBhYm91dCB0aGUgam9iIChgSm9iX0lEYCBhbmQgYEpvYl9OYW1lYCkuIFdlIGNhbiBqb2luIHRoZSB0d28gdGFibGUgb24gdGhlIG1hdGNoZWQgSUQgY29sdW1uIGBKb2JfSURgLg0KDQoqKlBlcnNvbiBUYWJsZSoqDQoNCmBgYHtyfQ0KDQpwZXJzb25fdGFibGUgPC0gZGF0YS5mcmFtZShQZXJzb25fSUQgPSBjKCJQZXJzb24xIiwgIlBlcnNvbjIiKSwgTmFtZSA9IGMoIkphbmUgRG9lIiwgIkpvaG4gU21pdGgiKSwgSm9iX0lEID0gYygiSm9iXzEiLCAiTkEiKSkNCg0KcGVyc29uX3RhYmxlDQpgYGANCg0KKipKb2IgVGFibGUqKiAgDQogICANCmBgYHtyfSAgICAgICAgICAgICAgICAgICAgICAgICAgIA0Kam9iX3RhYmxlIDwtIGRhdGEuZnJhbWUoSm9iX0lEID0gYygiSm9iXzEiLCAiSm9iXzIiKSwgSm9iX05hbWUgPSBjKCJQcm9ncmFtbWVyIiwgIlN0YXRpc3RpY2lhbiIpKQ0KDQpqb2JfdGFibGUNCmBgYA0KDQojIyMgSW5uZXIgam9pbjoNCg0KV2l0aCBhbiBpbm5lciBqb2luLCByb3dzIHdoZXJlIHRoZXJl4oCZcyBhIG1hdGNoIG9uIHRoZSBqb2luIGNyaXRlcmlhIGFyZSByZXR1cm5lZC4gVW5tYXRjaGVkIHJvd3MgYXJlIGV4Y2x1ZGVkLiBEb24ndCB3b3JyeSBhYm91dCB0aGUgd2FybmluZyBtZXNzYWdlLiBJdCBpcyBqdXN0IHBvaW50aW5nIG91dCB0aGF0IHRoZSBjb2x1bW4gYEpvYl9JRGAgaW4gdGhlIHBlcnNvbiB0YWJsZSBoYXMgDQoNCmBgYHtyIElubmVyIGpvaW4gZXhhbXBsZX0NCg0KaW5uZXJfam9pbih4ID0gcGVyc29uX3RhYmxlLCB5ID0gam9iX3RhYmxlLCBieSA9ICJKb2JfSUQiKQ0KDQpgYGANCg0KIyMjIExlZnQgam9pbjoNCg0KV2l0aCBhIGxlZnQgam9pbiwgeW91IGdldCBhbGwgcm93cyBmcm9tIHRoZSBsZWZ0IHNpZGUgb2YgdGhlIGpvaW4gZXZlbiBpZiB0aGVyZSBhcmUgbm8gbWF0Y2hpbmcgcm93cyBvbiB0aGUgcmlnaHQgc2lkZS4gWW91IG9ubHkgZ2V0IHJvd3MgZnJvbSB0aGUgcmlnaHQgc2lkZSB3aGVyZSB0aGVyZeKAmXMgYSBqb2luIG1hdGNoIHRvIGEgcm93IG9uIHRoZSBsZWZ0Lg0KDQpgYGB7ciBMZWZ0IGpvaW4gZXhhbXBsZX0NCg0KbGVmdF9qb2luKHggPSBwZXJzb25fdGFibGUsIHkgPSBqb2JfdGFibGUsIGJ5ID0gIkpvYl9JRCIpDQoNCmBgYA0KDQojIyMgUmlnaHQgam9pbjoNCg0KV2l0aCBhIHJpZ2h0IGpvaW4sIHlvdSBnZXQgYWxsIHRoZSByb3dzIGZyb20gdGhlIGxlZnQgc2lkZSBvZiB0aGUgam9pbiBvbmx5IHdoZXJlIHRoZXJl4oCZcyBhIG1hdGNoIG9uIHRoZSByaWdodC4gWW91IGdldCBhbGwgcm93cyBmcm9tIHRoZSByaWdodCBzaWRlIG9mIHRoZSBqb2luIGV2ZW4gaWYgdGhlcmUgYXJlIG5vIG1hdGNoaW5nIHJvd3Mgb24gdGhlIGxlZnQuDQoNCmBgYHtyIFJpZ2h0IGpvaW4gZXhhbXBsZX0NCg0KcmlnaHRfam9pbih4ID0gcGVyc29uX3RhYmxlLCB5ID0gam9iX3RhYmxlLCBieSA9ICJKb2JfSUQiKQ0KDQpgYGANCg0KIyMjIEZ1bGwgam9pbg0KDQpXaXRoIGEgZnVsbCBqb2luLCB5b3UgZ2V0IGFsbCByb3dzIGZyb20gdGhlIGxlZnQgYW5kIHJpZ2h0IGhhbmQgc2lkZSwgam9pbmVkIHdoZXJlIHRoZSBjcml0ZXJpYSBtYXRjaGVzLg0KDQpgYGB7ciBGdWxsIGpvaW4gZXhhbXBsZX0NCg0KZnVsbF9qb2luKHggPSBwZXJzb25fdGFibGUsIHkgPSBqb2JfdGFibGUsIGJ5ID0gIkpvYl9JRCIpDQoNCmBgYA0KDQojIyMgTWF0Y2hpbmcgdGhlIGdhcG1pbmRlciBkYXRhIHRvIGEgbmV3IGRhdGEgZnJhbWUgYHVrX2dkcFBlcmNhcF9kZmANCg0KKipDcmVhdGluZyB0aGUgbmV3IGRhdGEgZnJhbWUgYHVrX2dkcFBlcmNhcF9kZmAqKg0KDQpUbyBsb29rIGF0IHRoZSBwZXIgY2FwaXRhIEdEUCBpbiBhIHdheSB0aGF0J3MgbW9yZSBtZWFuaW5nZnVsLCBsZXQncyBjcmVhdGUgYSBuZXcgdmFyaWFibGUgYGdkcFBlcmNhcF9yZWxgLCB0aGF0IGlzIHRoZSBgZ2RwUGVyY2FwYCBvZiB0aGUgY291bnRyeSByZWxhdGl2ZSB0byB0aGUgVW5pdGVkIEtpbmRvbSBgZ2RwUGVyY2FwYCBvZiB0aGF0IHNhbWUgeWVhci4gDQoNCldlIGNhbiBkbyB0aGlzIGJ5IGRpdmlkaW5nIGBnZHBQZXJjYXBgIGJ5IHRoZSBVbml0ZWQgS2luZ2RvbSdzIGBnZHBQZXJjYXBgLCBtYWtpbmcgc3VyZSB0aGF0IHdlIGFsd2F5cyBkaXZpZGUgdHdvIG51bWJlcnMgdGhhdCBhcmUgZnJvbSB0aGUgc2FtZSB5ZWFyLiBUbyBkbyB0aGlzIHdlIG5lZWQgdG8gZmlyc3Q6DQoNCjEuIENyZWF0ZSBhIG5ldyBkYXRhZnJhbWUgYHVrX2dkcFBlcmNhcF9kZmANCjIuIEZpbHRlciB0aGUgcm93cyBmb3IgYGNvdW50cnkgPT0gIlVuaXRlZCBLaW5nZG9tImAuDQozLiBTZWxlY3QgdGhlIGNvbHVtbnMgYGdkcFBlcmNhcGAgYW5kIGB5ZWFyYC4gDQo0LiBSZW5hbWUgdGhlIHZhcmlhYmxlIGBnZHBQZXJjYXBgLCBgdWtfZ2RwUGVyY2FwYC4NCg0KDQpgYGB7ciBNYWtlIGEgbmV3IGRhdGEgZnJhbWUgdWtfZ2RwUGVyY2FwX2RmfQ0KDQp1a19nZHBQZXJjYXBfZGYgPC0gZ2FwbWluZGVyICU+JQ0KICBmaWx0ZXIoY291bnRyeSA9PSAiVW5pdGVkIEtpbmdkb20iKSAlPiUNCiAgc2VsZWN0KGdkcFBlcmNhcCwgeWVhcikgJT4lDQogIHJlbmFtZSh1a19nZHBQZXJjYXAgPSBnZHBQZXJjYXApDQoNCmhlYWQodWtfZ2RwUGVyY2FwX2RmKQ0KDQpgYGANCldlIHdhbnQgdG8gZGl2aWRlIGFsbCB0aGUgb3RoZXIgZ2RwUGVyY2FwIGJ5IHRoZSBVSyBgZ2RwUGVyY2FwYCBpbiB0aGF0IHNhbWUgeWVhci4NCg0KT25lIHdheSB3ZSBjYW4gZG8gdGhpcyBpcyB0byBtYXRjaCB0aGUgdHdvIGRhdGEgZnJhbWVzIHVzaW5nIGEgYGxlZnRfam9pbmAgb24gdGhlIGNvbW1vbiB2YXJpYWJsZSwgeWVhci4gVGhpcyB3aWxsIGVmZmVjdGl2ZWx5IG1ha2UgYSBuZXcgY29sdW1uLCBmb3IgdGhlIGB1a19nZHBQZXJjYXBgIHRoYXQgaXMgam9pbmVkIHVwIHRvIG91ciBgZ2FwbWluZGVyYCBkYXRhIGZyYW1lLg0KDQpBIGBsZWZ0X2pvaW5gIGtlZXBzIGFsbCBvZiB0aGUgcm93cyBmcm9tIHRoZSBmaXJzdCBkYXRhIGZyYW1lICh4ID0gZ2FwbWluZGVyKSBhbmQgb24gdGhlIG1hdGNoaW5nIHJvd3MgZnJvbSB0aGUgb3RoZXIgZGF0YSBmcmFtZSAoeSA9IHVrX2dkcFBlcmNhcF9kZiksIHVzaW5nIHRoZSB2YWx1ZXMgaW4gdGhlIGNvbHVtbiBgeWVhcmAgdG8gZG8gdGhlIG1hdGNoaW5nIChgYnkgPSAieWVhciJgKS4gDQoNCg0KYGBge3IgSm9pbiB0aGUgZ2FwbWluZGVyIGFuZCB1a19nZHBQZXJjYXBfZGYgZGF0YSBmcmFtZXN9DQoNCmdhcG1pbmRlciA8LSBsZWZ0X2pvaW4oZ2FwbWluZGVyLCB1a19nZHBQZXJjYXBfZGYsIGJ5ID0gInllYXIiKQ0KDQpoZWFkKGdhcG1pbmRlclssIGMoImNvdW50cnkiLCAieWVhciIsICJ1a19nZHBQZXJjYXAiLCAiZ2RwUGVyY2FwIildKQ0KDQpgYGANCg0KTm93IHRoYXQgd2UgaGF2ZSB0aGUgYGdkcFBlcmNhcGAgYW5kIGB1a19nZHBQZXJjYXBgIG1hdGNoZWQgdXAsIHdlIGNhbiBjYW4gY2FsY3VsYXRlIHRoZSByZWxhdGl2ZSBHRFAgcGVyIGNhcGl0YSBgZ2RwUGVyY2FwX3JlbGAuIA0KDQpgYGB7ciBNYWtlIGEgbmV3IHZhcmlhYmxlIGdkcFBlcmNhcF9yZWx9DQoNCmdhcG1pbmRlciA8LSBnYXBtaW5kZXIgJT4lDQogIG11dGF0ZShnZHBQZXJjYXBfcmVsID0gZ2RwUGVyY2FwL3VrX2dkcFBlcmNhcCkNCg0KYGBgDQoNCldlIGNhbiBkb3VibGVjaGVjayB0aGF0IG91ciBjYWxjdWxhdGlvbiB3b3JrZWQgYnkgZmlsdGVyaW5nIGZvciB0aGUgVW5pdGVkIEtpbmdkb20gdG8gY2hlY2sgdGhhdCB0aGUgcmVsYXRpdmUgZ2RwIHBlciBjYXBpdGEgaXMgMS4gDQoNCmBgYHtyIERvdWJsZWNoZWNraW5nIG91ciBjYWxjdWxhdGlvbiBvZiBnZHBQZXJjYXBfcmVsIHdvcmtlZH0NCg0KZ2FwbWluZGVyICU+JQ0KICBmaWx0ZXIoY291bnRyeSA9PSAiVW5pdGVkIEtpbmdkb20iKSAlPiUNCiAgc2VsZWN0KGdkcFBlcmNhcF9yZWwpICU+JQ0KICBoZWFkKCkNCg0KYGBgDQoNCkhvdyBtYW55IGNvdW50cmllcyBoYWQgYSBzbWFsbGVyIGdkcCBwZXIgY2FwaXRhIHRoYW4gdGhlIFVLIGVhY2ggeWVhcj8NCg0KYGBge3IgSG93IG1hbnkgY291bnRyaWVzIGhhZCBhIHNtYWxsZXIgZ2RwUGVyY2FwaXRhfQ0KDQpnYXBtaW5kZXIgJT4lDQogIGdyb3VwX2J5KHllYXIpICU+JQ0KICBmaWx0ZXIoZ2RwUGVyY2FwX3JlbCA8PSAxKSAlPiUNCiAgc3VtbWFyaXNlKGNvdW50ID0gbigpKQ0KDQpgYGANCg0KDQojIyMgKipFeGVyY2lzZXMqKg0KDQoxLiBXaGF0IGRvZXMgdGhlIGZvbGxvd2luZyBiaXQgb2YgY29kZSBkbz8NCg0KYGBge3IgMS4gU2VsZWN0IDIuIGZpbHRlciAzLiBncm91cF9ieSBhbmQgNC4gc3VtbWFyaXNlLCBldmFsID0gRkFMU0V9DQoNCmdhcG1pbmRlciAlPiUNCiAgc2VsZWN0KGNvdW50cnksIGdkcFBlcmNhcF9yZWwpICU+JQ0KICBmaWx0ZXIoY291bnRyeSAlaW4lIGMoIkFyZ2VudGluYSIsICJDaGlsZSIsICJQZXJ1IiwgIkJyYXppbCIpKSAlPiUNCiAgZ3JvdXBfYnkoY291bnRyeSkgJT4lDQogIHN1bW1hcmlzZSgNCiAgICAgICAgICAgIG1heF9nZHAgPSBtYXgoZ2RwUGVyY2FwX3JlbCksIA0KICAgICAgICAgICAgbWluX2dkcCA9IG1pbihnZHBQZXJjYXBfcmVsKSwgDQogICAgICAgICAgICBtZWFuX2dkcCA9IG1lYW4oZ2RwUGVyY2FwX3JlbCkNCiAgICAgICAgICAgICkNCg0KYGBgDQoNCg0KMi4gSG93IG1hbnkgY291bnRyaWVzIGhhZCBhIGhpZ2hlciByZWxhdGl2ZSBnZHAgcGVyIGNhcGl0YSB0aGFuIHRoZSBVbml0ZWQgS2luZG9tIHBlciB5ZWFyPw0KDQpgYGB7ciBIb3cgbWFueSBjb3VudHJpZXMgaGFkIGEgaGlnaGVyIHJlbGF0aXZlIGdkcCBwZXIgY2FwaXRhLCBldmFsID0gRkFMU0V9DQoNCmdhcG1pbmRlciAlPiUNCiAgZ3JvdXBfYnkoKSAlPiUNCiAgZmlsdGVyKGdkcFBlcmNhcF9yZWwgPiAxKSAlPiUNCiAgc3VtbWFyaXNlKGNvdW50ID0gbigpKQ0KDQpgYGANCg0KMy4gV2hpY2ggY291bnRyaWVzIGhhdmUgYSBoaWdoZXIgZ2RwIHBlciBjYXBpdGEgdGhhbiB0aGUgVUs/IEZpbGwgaW4gdGhlIGJsYW5rcw0KDQpgYGB7ciBXaGljaCBjb3VudHJpZXMgaGFkIGEgaGlnaGVyIGdkcCBwZXIgY2FwaXRhIHRoYW4gdGhlIFVLLCBldmFsID0gRkFMU0V9DQoNCmdhcG1pbmRlciAlPiUNCiAgZmlsdGVyKDxCTEFOSz4pICU+JQ0KICBzZWxlY3QoY291bnRyeSkgJT4lDQogIHVuaXF1ZSgpDQoNCmBgYA0KDQojIyMgQW5zd2VycyB0byBvdXIgcG9sbCANCg0KVXNpbmcgd2hhdCB3ZSd2ZSBsZWFybmVkIHNvIGZhciwgbGV0J3MgZ28gYmFjayB0byBvdXIgb3JpZ2luYWwgY29tcGFyaXNvbnMuDQoNCldoaWNoIG9mIHRoZSB0aHJlZSBwYWlycyBvZiBjb3VudHJpZXMgZG8geW91IHRoaW5rIGhhdmUgYSBoaWdoZXIgaW5mYW50IG1vcnRhbGl0eSByYXRlIGluIDIwMDc/IFdoaWNoIGFyZSB0aGUgbW9zdCBzaW1pbGFyPw0KDQoxLiBTcmkgTGFua2Egb3IgVHVya2V5DQoNCmBgYHtyIFR1cmtleSBvciBTcmkgTGFua2E6IHdobyBoYXMgYSBoaWdoZXIgaW5mYW50IG1vcnRhbGl0eSByYXRlIGluIDIwMDcsIGV2YWwgPSBGQUxTRX0NCg0KZ2FwbWluZGVyICU+JQ0KICBmaWx0ZXIoeWVhciA9PSAyMDA3LCBjb3VudHJ5ICVpbiUgYygiU3JpIExhbmthIiwgIlR1cmtleSIpKSAlPiUNCiAgc2VsZWN0KGNvdW50cnksIGluZmFudF9tb3J0YWxpdHkpDQoNCmBgYA0KDQoyLiBQb2xhbmQgb3IgTWFsYXlzaWENCg0KYGBge3IgUG9sYW5kIG9yIE1hbGF5c2lhOiB3aG8gaGFzIGEgaGlnaGVyIGluZmFudCBtb3J0YWxpdHkgcmF0ZSBpbiAyMDA3LCBldmFsID0gRkFMU0V9DQoNCmdhcG1pbmRlciAlPiUNCiAgZmlsdGVyKHllYXIgPT0gMjAwNywgY291bnRyeSAlaW4lIGMoIlBvbGFuZCIsICJNYWxheXNpYSIpKSAlPiUNCiAgc2VsZWN0KGNvdW50cnksIGluZmFudF9tb3J0YWxpdHkpDQoNCg0KYGBgDQoNCjMuIFBha2lzdGFuIG9yIFZpZXRuYW0NCg0KDQpgYGB7ciBQYWtpc3RhbiBvciBWaWV0bmFtOiB3aG8gaGFzIGEgaGlnaGVyIGluZmFudCBtb3J0YWxpdHkgcmF0ZSBpbiAyMDA3LCBldmFsID0gRkFMU0V9DQoNCmdhcG1pbmRlciAlPiUNCiAgZmlsdGVyKHllYXIgPT0gMjAwNywgY291bnRyeSAlaW4lIGMoIlBha2lzdGFuIiwgIlZpZXRuYW0iKSkgJT4lDQogIHNlbGVjdChjb3VudHJ5LCBpbmZhbnRfbW9ydGFsaXR5KQ0KDQpgYGANCg0KV2hpY2ggb2YgdGhlIHR3byBwYWlycyBvZiBjb3VudHJpZXMgZG8geW91IHRoaW5rIGhhdmUgYSBoaWdoZXIgbGlmZSBFeHBlY3RhbmN5IGluIDIwMDc/IFdoaWNoIGFyZSB0aGUgbW9zdCBzaW1pbGFyPw0KDQoxLiBTb3V0aCBBZnJpY2Egb3IgWWVtZW4NCg0KYGBge3IgU291dGggQWZyaWNhIG9yIFllbWVuOiB3aG8gaGFzIHRoZSBoaWdoZXN0IGxpZmUgRXhwZWN0YW5jeX0NCg0KZ2FwbWluZGVyICU+JQ0KICBmaWx0ZXIoeWVhciA9PSAyMDA3LCBjb3VudHJ5ICVpbiUgYygiU291dGggQWZyaWNhIiwgIlllbWVuLCBSZXAuIikpICU+JQ0KICBzZWxlY3QoY291bnRyeSwgbGlmZUV4cCkNCg0KYGBgDQoNCjIuIENoaWxlIG9yIEh1bmdhcnkNCg0KYGBge3IgQ2hpbGUgb3IgSHVuZ2FyeTogd2hvIGhhcyB0aGUgaGlnaGVzdCBsaWZlIEV4cGVjdGFuY3ksIGV2YWwgPSBGQUxTRX0NCg0KZ2FwbWluZGVyICU+JQ0KICBmaWx0ZXIoeWVhciA9PSAyMDA3LCBjb3VudHJ5ICVpbiUgYygiQ2hpbGUiLCAiSHVuZ2FyeSIpKSAlPiUNCiAgc2VsZWN0KGNvdW50cnksIGxpZmVFeHApDQoNCmBgYA0KDQoNCkZvciB0aGUgdHdvIHBhaXJzIG9mIGNvdW50cmllcyBiZWxvdywgd2hpY2ggY291bnRyeSBkbyB5b3UgdGhpbmsgaGFkIHRoZSBoaWdoZXN0IGdkcFBlcmNhcCBpbiAyMDA3Pw0KDQoxLiBTd2l0emVybGFuZCBvciBLdXdhaXQNCg0KYGBge3IgU3dpdHplcmxhbmQgb3IgS3V3YWl0OiB3aG8gaGFzIHRoZSBoaWdoZXN0IGdkcFBlcmNhcCwgZXZhbCA9IEZBTFNFfQ0KDQpnYXBtaW5kZXIgJT4lDQogIGZpbHRlcih5ZWFyID09IDIwMDcsIGNvdW50cnkgJWluJSBjKCJTd2l0emVybGFuZCIsICJLdXdhaXQiKSkgJT4lDQogIHNlbGVjdChjb3VudHJ5LCBnZHBQZXJjYXApDQoNCmBgYA0KDQoyLiBDb2xvbWJpYSBvciBOZXBhbA0KDQoNCmBgYHtyIENvbG9tYmlhIG9yIE5lcGFsOiB3aG8gaGFzIHRoZSBoaWdoZXN0IGdkcFBlcmNhcCwgZXZhbCA9IEZBTFNFfQ0KDQpnYXBtaW5kZXIgJT4lDQogIGZpbHRlcih5ZWFyID09IDIwMDcsIGNvdW50cnkgJWluJSBjKCJDb2xvbWJpYSIsICJOZXBhbCIpKSAlPiUNCiAgc2VsZWN0KGNvdW50cnksIGdkcFBlcmNhcCkNCg0KYGBgDQoNCg0KV2hpY2ggcmVzdWx0cyBkaWQgeW91IGZpbmQgdGhlIG1vc3Qgc3VycHJpc2luZz8NCg0KDQojIEludHJvIHRvIERhdGEgVmlzdWFsaXNhdGlvbiBVc2luZyBnZ3Bsb3QyDQoNCk9uZSBvZiB0aGUgbW9zdCBtZWFuaW5nZnVsIHdheXMgdG8gaW50ZXJwcmV0IGFuZCBtYWtlIHNlbnNlIG9mIGRhdGEgaXMgdGhyb3VnaCBwbG90dGluZyEgUGxvdHRpbmcgdGhlIGRhdGEgYWxsb3dzIHVzIHRvIGxvb2sgZm9yIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiB2YXJpYWJsZXMsIGdlbmVyYXRlIGh5cG90aGVzZXMsIGFuZCBpZGVudGlmaWVkIHBhdHRlcm5zLiBBIGdyZWF0IHBhY2thZ2UgdG8gbWFrZSBhdHRyYWN0aXZlIGdyYXBoaWNzIGlzIGdncGxvdDIuIA0KDQpMZXQncyBzdGFydCBieSBtYWtpbmcgYSBzY2F0dGVyIHBsb3Qgb2YgbGlmZSBFeHBlY3RhbmN5IGJ5IHllYXIgZm9yIGEgaGFuZGZ1bCBvZiBjb3VudHJpZXMgaW4gdGhlIG1pZGRsZSBlYXN0Lg0KDQpGaXJzdCB3ZSBjYW4gbWFrZSBhIG5ldyBkYXRhZnJhbWUgY2FsbGVkIGBnYXBtaW5kZXJfbWlkZGxlX2Vhc3RgDQoNCmBgYHtyIENyZWF0aW5nIGEgbmV3IGRhdGEgZnJhbWU6IGdhcG1pbmRlcl9taWRkbGVfZWFzdH0NCg0KbWlkZGxlX2Vhc3QgPC0gYygiSXNyYWVsIiwgIkpvcmRhbiIsICJPbWFuIiwgICJZZW1lbiwgUmVwLiIpDQoNCmdhcG1pbmRlcl9taWRkbGVfZWFzdCA8LSBnYXBtaW5kZXIgJT4lDQogIGZpbHRlcihjb3VudHJ5ICVpbiUgbWlkZGxlX2Vhc3QpDQoNCmBgYA0KDQojIyMgQ3JlYXRpbmcgYSBzY2F0dGVyIHBsb3QgdXNpbmcgZ2dwbG90Mg0KDQpUaGVuIHdlIGNhbiBtYWtlIGEgc2NhdHRlciBwbG90IGluIGdncGxvdDIgdXNpbmcgdGhlIGZ1bmN0aW9uIGdlb21fcG9pbnQgcGxvdHRpbmcgYHllYXJgIG9uIHRoZSB4IGF4aXMgYW5kIGBsaWZlRXhwYCBvbiB0aGUgeSBheGlzLiANCg0KYGBge3IgQmFzaWMgU2NhdHRlcnBsb3QgaW4gZ2dwbG90fQ0KDQpnZ3Bsb3QoZGF0YSA9IGdhcG1pbmRlcl9taWRkbGVfZWFzdCkgKw0KICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IHllYXIsIHkgPSBsaWZlRXhwKSkNCg0KYGBgDQoNCiMjIGdncGxvdCBzdHJ1Y3R1cmUNCg0KVG8gbWFrZSBhIHBsb3Qgd2l0aCBgZ2dwbG90MmAgeW91IGJlZ2luIGEgcGxvdCB3aXRoIHRoZSBmdW5jdGlvbiBgZ2dwbG90KClgOiANCg0KKiBgZ2dwbG90KClgDQoNClRoZSBmaXJzdCBhcmd1bWVudCBvZiBgZ2dwbG90KClgIGlzIHRoZSBkYXRhc2V0IHRvIHVzZSBpbiB0aGUgZ3JhcGg6IA0KDQoqIGBnZ3Bsb3QoZGF0YSA9IGdhcG1pbmRlcl9taWRkbGVfZWFzdClgIA0KDQpZb3UgY29tcGxldGUgeW91ciBncmFwaCBieSBhZGRpbmcgb25lIG9yIG1vcmUgbGF5ZXJzIHRvIGBnZ3Bsb3QoKWAuDQoNCiogZS5nLiBgZ2VvbV9wb2ludCgpYC4gDQoNClRoZSBmdW5jdGlvbiBgZ2VvbV9wb2ludCgpYCBhZGRzIGEgbGF5ZXIgb2YgcG9pbnRzIHRvIHlvdXIgcGxvdC4gRWFjaCBgZ2VvbWAgZnVuY3Rpb24gaW4gZ2dwbG90MiB0YWtlcyBhIGBtYXBwaW5nYCBhcmd1bWVudCB3aGljaCBkZWZpbmVzIGhvdyB2YXJpYWJsZXMgaW4geW91ciBkYXRhc2V0IGFyZSBtYXBwZWQgdG8gdmlzdWFsIHByb3BlcnRpZXMuIFRoZSBgbWFwcGluZ2AgYXJndW1lbnQgaXMgYWx3YXlzIHBhaXJlZCB3aXRoIGBhZXMoKWAuIEluIHRoZSBjYXNlIG9mIGBnZW9tX3BvaW50YCB0aGUgYHhgIGFuZCBgeWAgYXJndW1lbnRzIG9mIGBhZXMoKWAgc3BlY2lmeSB3aGljaCB2YXJpYWJsZXMgdG8gKm1hcCogdG8gdGhlIHggYW5kIHkgYXhlcy4gDQoNCiogYGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0geWVhciwgeSA9IGxpZmVFeHApKWAuIA0KDQpXaGVuIHRoZXNlIGFyZSBzcGVjaWZpZWQsIGdncGxvdDIgbG9va3MgZm9yIHRoZSBtYXBwZWQgdmFyaWFibGVzIChgeWVhcmAgYW5kIGBsaWZlRXhwYCkgaW4gdGhlIGBkYXRhYCBhcmd1bWVudC4NCg0KDQojIyBHcmFwaGluZyB0ZW1wbGF0ZQ0KDQpHcmFwaHMgaW4gZ2dwbG90IHRha2UgdGhlIGZvbGxvd2luZyBmb3JtDQoNCmBgYHtyIGdncGxvdDIgZ3JhcGhpbmcgdGVtcGxhdGUsIGV2YWwgPSBGQUxTRX0NCmdncGxvdChkYXRhID0gPERBVEE+KSArIA0KICA8R0VPTV9GVU5DVElPTj4obWFwcGluZyA9IGFlcyg8TUFQUElOR1M+KSkNCmBgYA0KDQpEZXBlbmRpbmcgb24gdGhlIGA8R0VPTV9GVU5DVElPTj5gIHVzZWQgdGhlIGFyZ3VtZW50cyBtYXkgdmFyeS4gRm9yIGluc3RhbmNlIGlmIHdlIGFyZSBwbG90dGluZyBhIGhpc3RvZ3JhbSB0byBsb29rIGF0IHRoZSByYW5nZSBvZiBsaWZlIEV4cGVjdGFuY3kgaW4gdGhlIGRhdGFzZXQsIHdlIG9ubHkgbmVlZCB0byBwcm92aWRlIGEgdmFyaWFibGUgZm9yIHRoZSB4IGF4aXMuIFdlIGFsc28gbmVlZCB0byBwcm92aWRlIGEgdmFsdWUgZm9yIHRoZSBhcmd1bWVudCBgYmlucygpYC4NCg0KYGBge3IgVHJ5aW5nIGEgbmV3IGdlb20gZnVuY3Rpb24gdG8gbWFrZSBhIGhpc3RvZ3JhbX0NCg0KZ2dwbG90KGRhdGEgPSBnYXBtaW5kZXIpICsNCiAgZ2VvbV9oaXN0b2dyYW0obWFwcGluZyA9IGFlcyh4ID0gbGlmZUV4cCksIGJpbnMgPSAyNSkNCg0KYGBgDQoNClRha2UgYSBsb29rIGF0IHdoYXQgZGlmZmVyZW50IHBsb3RzIGFyZSBhdmFpbGFibGUgYnkgdHlwaW5nIGBnZW9tX2AgYW5kIHRoZW4gdGFiLiANCg0KIyMjIEFlc3RoZXRpYyBtYXBwaW5ncw0KDQpZb3UgY2FuIGFkZCBhIHRoaXJkIHZhcmlhYmxlLCBsaWtlIGBjb3VudHJ5YCwgdG8gYSB0d28gZGltZW5zaW9uYWwgc2NhdHRlcnBsb3QgYnkgbWFwcGluZyBpdCB0byBhbiAqKmFlc3RoZXRpYyoqLiAqKkFlc3RoZXRpY3MqKiBhcmUgdmlzdWFsIHByb3BlcnRpZXMgb2YgdGhlIG9iamVjdHMgaW4geW91ciBwbG90LiBBZXN0aGV0aWNzIGluY2x1ZGUgdGhpbmdzIGxpa2UgdGhlIHNpemUsIHRoZSBzaGFwZSwgb3IgdGhlIGNvbG9yIG9mIHlvdXIgcG9pbnRzLiBZb3UgY2FuIGRpc3BsYXkgYSBwb2ludCAobGlrZSB0aGUgb25lIGJlbG93KSBpbiBkaWZmZXJlbnQgd2F5cyBieSBjaGFuZ2luZyB0aGUgdmFsdWVzIG9mIGl0cyBhZXN0aGV0aWMgcHJvcGVydGllcy4gDQoNCkl0IHNlZW1zIGxpa2Ugb3ZlcmFsbCwgbGlmZSBleHBlY3RhbmN5IChgbGlmZUV4cGApIGhhcyBiZWVuIGltcHJvdmluZyBpbiBtb3N0IGNvdW50cmllcyB3aXRoIHRpbWUsIGJ1dCBzb21lIGFyZSBpbXByb3ZpbmcgZmFzdGVyIHRoYW4gb3RoZXJzLiBXZSBjYW4gYWRkIGFkZGl0aW9uYWwgaW5mb3JtYXRpb24gdG8gdGhlIGBhZXNgIGFyZ3VtZW50IHRvIGV4cGxvcmUgdGhlIGRhdGEgZnVydGhlci4gRm9yIGluc3RhbmNlLCB3ZSBjYW4gY29sb3VyIHRoZSBwb2ludHMgYnkgY291bnRyeS4NCg0KIyMjIyBDb2xvdXJpbmcgcG9pbnRzIGJ5IGEgZmFjdG9yDQoNCmBgYHtyIE1ha2UgYSBzY2F0dGVyIHBsb3Qgd2l0aCBwb2ludHMgY29sb3VyZWQgYnkgY291bnRyeX0NCg0KZ2dwbG90KGRhdGEgPSBnYXBtaW5kZXJfbWlkZGxlX2Vhc3QpICsNCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSB5ZWFyLCB5ID0gbGlmZUV4cCwgY29sb3VyID0gY291bnRyeSkpDQoNCmBgYA0KDQoNClRoaXMgbWFrZXMgdGhlIGdyYXBoIGEgbGl0dGxlIGVhc2llciB0byByZWFkLCBidXQgc29tZSBvZiB0aGUgY29sb3VycyBibGVuZCB0b2dldGhlci4gV2UgY2FuIGFkZCBhbiBhZGRpdGlvbmFsIGFyZ3VtZW50IHRvIGNoYW5nZSB0aGUgc2hhcGUgb2YgdGhlIHBvaW50IGFzIHdlbGwuIA0KDQojIyMjIENoYW5naW5nIHBvaW50IHNoYXBlIGJ5IGEgZmFjdG9yDQoNCmBgYHtyIE1ha2UgYSBzY2F0dGVycGxvdCB3aXRoIGNvbG91ciBhbmQgc2hhcGUgc2V0IGJ5IGNvdW50cnl9DQoNCmdncGxvdChkYXRhID0gZ2FwbWluZGVyX21pZGRsZV9lYXN0KSArDQogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0geWVhciwgeSA9IGxpZmVFeHAsIGNvbG91ciA9IGNvdW50cnksIHNoYXBlID0gY291bnRyeSkpDQoNCmBgYA0KDQojIyMjIENoYW5naW5nIHBvaW50IHNpemUgZXF1YWwgdG8gYSBudW1lcmljIHZhcmlhYmxlDQoNCldlIGNhbiBhbHNvIGNoYW5nZSB0aGUgc2l6ZSwgbWFraW5nIGl0IGVxdWFsIHRvIGdkcFBlcmNhcA0KDQpgYGB7ciBNYWtlIGEgcGxvdCB3aXRoIHNpemUgc2V0IGJ5IGdkcFBlcmNhcH0NCg0KZ2dwbG90KGRhdGEgPSBnYXBtaW5kZXJfbWlkZGxlX2Vhc3QpICsNCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSB5ZWFyLCB5ID0gbGlmZUV4cCwgY29sb3VyID0gY291bnRyeSwgc2l6ZSA9IGdkcFBlcmNhcCkpDQoNCmBgYA0KDQpJbiB0aGlzIGNhc2UgYGdncGxvdGAgZ2l2ZXMgdXMgdHdvIGxlZ2VuZHMsIG9uZSBmb3IgdGhlIHNpemUgb2YgdGhlIHBvaW50cyBhbmQgb25lIGZvciB0aGUgY291bnRyeSBjb2xvdXIuIE1vc3Qgb2YgdGhlIGNvdW50cmllcyBgZ2RwUGVyY2FwYCBoYXMgYmVlbiBpbmNyZWFzaW5nIG92ZXJ0aW1lLCBhbHRob3VnaCBzb21lIGluY3JlYXNlcyBhcmUgbW9yZSBzbGlnaHQgdGhhbiBvdGhlcnMuIA0KDQpXZSBjb3VsZCBhbHNvIG1ha2UgdGhlIHBsb3Qgd2l0aCB0aGUgcG9pbnRzIHNpemVkIGJ5IHJlbGF0aXZlIGdkcCBwZXIgY2FwaXRhIGBnZHBQZXJjYXBfcmVsYA0KDQoNCmBgYHtyIE1ha2UgYSBwbG90IHdpdGggc2l6ZSBlcXVhbCB0byByZWxhdGl2ZSBnZHBQZXJjYXB9DQoNCmdncGxvdChkYXRhID0gZ2FwbWluZGVyX21pZGRsZV9lYXN0KSArDQogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0geWVhciwgeSA9IGxpZmVFeHAsIGNvbG91ciA9IGNvdW50cnksIHNpemUgPSBnZHBQZXJjYXBfcmVsKSkNCg0KYGBgDQoNCiMjIyMgQWRkaW5nIHRpdGxlcyBhbmQgbGFiZWxzDQoNCldlIGNhbiBjdXN0b21pc2Ugb3VyIGdyYXBoIGZ1cnRoZXIgYnkgYWRkaW5nIHRpdGxlcyBhbmQgbGFiZWxzLg0KDQpgYGB7ciBDdXN0b21pc2UgYSBnZ3Bsb3Qgd2l0aCB0aXRsZXMgYW5kIGxhYmVsc30NCg0KZ2dwbG90KGRhdGEgPSBnYXBtaW5kZXJfbWlkZGxlX2Vhc3QpICsNCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSB5ZWFyLCB5ID0gbGlmZUV4cCwgY29sb3VyID0gY291bnRyeSwgc2l6ZSA9IGdkcFBlcmNhcCkpICsNCiAgZ2d0aXRsZSgiTGlmZSBFeHBlY3RhbmN5IGJ5IFllYXIiKSArDQogIGxhYnMoeCA9ICJZZWFyIiwgeSA9ICJMaWZlIEV4cGVjdGFuY3kiKQ0KDQpgYGANCg0KIyMjIyBDaGFuZ2luZyB0aGUgbGltaXRzIG9mIG91ciBheGVzDQoNCldlIGNhbiBhbHNvIGNoYW5nZSB0aGUgbGltaXRzIG9mIG91ciB4IGFuZCB5IGF4ZXMuIEdlbmVyYWxseSBpdCBpcyBhIGdvb2QgaWRlYSB0byBzdGFydCBheGVzIGZyb20gMC4gDQoNCg0KYGBge3IgQ2hhbmdlIHRoZSBsaW1pdHMgb2YgdGhlIHggYW5kIHkgYXhlc30NCg0KZ2dwbG90KGRhdGEgPSBnYXBtaW5kZXJfbWlkZGxlX2Vhc3QpICsNCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSB5ZWFyLCB5ID0gbGlmZUV4cCwgY29sb3VyID0gY291bnRyeSwgc2l6ZSA9IGdkcFBlcmNhcCkpICsNCiAgZ2d0aXRsZSgiTGlmZSBFeHBlY3RhbmN5IGJ5IFllYXIiKSArDQogIGxhYnMoeCA9ICJZZWFyIiwgeSA9ICJMaWZlIEV4cGVjdGFuY3kiKSArDQogIHlsaW0oMCwgMTAwKQ0KDQpgYGANCg0KIyMjIyBDaGFuZ2UgdGhlIGxhYmVscyBvbiBhIGxlZ2VuZA0KDQpXZSBjYW4gYWxzbyBjaGFuZ2UgdGhlIGxhYmVscyBvZiBvdXIgbGVnZW5kLiANCg0KYGBge3IgQ2hhbmdlIHRoZSBsYWJlbHMgb2YgdGhlIGxlZ2VuZH0NCg0KZ2dwbG90KGRhdGEgPSBnYXBtaW5kZXJfbWlkZGxlX2Vhc3QpICsNCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSB5ZWFyLCB5ID0gbGlmZUV4cCwgY29sb3VyID0gY291bnRyeSwgc2l6ZSA9IGdkcFBlcmNhcCkpICsNCiAgZ2d0aXRsZSgiTGlmZSBFeHBlY3RhbmN5IGJ5IFllYXIiKSArDQogIGxhYnMoeCA9ICJZZWFyIiwgeSA9ICJMaWZlIEV4cGVjdGFuY3kiLCBjb2xvdXIgPSAiQ291bnRyeSIsIHNpemUgPSAiR0RQIFBlciBDYXBpdGEiKSArDQogIHlsaW0oMCwgMTAwKQ0KICANCmBgYA0KDQojIyMjIE1ha2UgbXVsdGlwbGUgcGxvdHMgdXNpbmcgYGZhY2V0X3dyYXAoKWANCg0KVGhlIGZ1bmN0aW9uIGBmYWNldF93cmFwKClgIHdyYXBzIGEgc2VyaWVzIG9mIHBsb3QgcGFuZWxzIGludG8gdHdvIGRpbWVuc2lvbnMuIFdlIGNhbiB1c2UgaXQgaW4gb3VyIHBsb3QgdG8gbWFrZSBhIHBsb3QgcGFuZWwgZm9yIGVhY2ggY291bnRyeS4gVGhlcmUgYXJlIG90aGVyIG9wdGlvbnMgZm9yIGZhY2V0X3dyYXAsIHRha2UgYSBsb29rIGF0IHRoZSBoZWxwIGZpbGUgYnkgdHlwaW5nIGA/ZmFjZXRfd3JhcGAgdG8gbG9vayBhdCBvdGhlciBleGFtcGxlcyBsaWtlIHdyYXBwaW5nIHRoZSBkYXRhIGJ5IHR3byB2YXJpYWJsZXMuIA0KDQpgYGB7ciBNYWtlIGEgZmFjZXQgZ3JpZCBwbG90fQ0KDQpwMSA8LSBnZ3Bsb3QoZGF0YSA9IGdhcG1pbmRlcl9taWRkbGVfZWFzdCkgKw0KICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IHllYXIsIHkgPSBsaWZlRXhwLCBjb2xvdXIgPSBjb3VudHJ5LCBzaXplID0gZ2RwUGVyY2FwKSkgKw0KICBnZ3RpdGxlKCJMaWZlIEV4cGVjdGFuY3kgYnkgWWVhciIpICsNCiAgbGFicyh4ID0gIlllYXIiLCB5ID0gIkxpZmUgRXhwZWN0YW5jeSIsIHNpemUgPSAiR0RQIFBlciBDYXBpdGEiLCBjb2xvdXIgPSAiQ291bnRyeSIpICsNCiAgeWxpbSgwLCAxMDApIA0KDQpwMSArIGZhY2V0X3dyYXAofmNvdW50cnksIG5jb2wgPSAyKQ0KYGBgDQogDQpBbmQgdG8gc2F2ZSB0aGUgbGFzdCBwbG90IHdlIG1hZGUsIHdlIGNhbiBydW4gdGhlIGZvbGxvd2luZyBsaW5lcyBvZiBjb2RlLiAgDQoNCiMjIyMgU2F2ZSBhIHBsb3QgdXNpbmcgYGdnc2F2ZSgpYA0KIA0KYGBge3IgU2F2ZSBhIHBsb3QgdXNpbmcgZ2dzYXZlKCl9ICANCg0KZ2dzYXZlKGZpbGVuYW1lID0gInBpY3R1cmVzL0xpZmVfRXhwZWN0YW5jeV9ieV9ZZWFyLnBuZyIsIHdpZHRoID0gNiwgaGVpZ2h0ID0gNCkNCg0KYGBgDQoNCkZyb20gdGhpcyBwbG90IGl0IHNlZW1zIGxpa2UgdGhlIGNvdW50cmllcyB3aXRoIHRoZSBsYXJnZXN0IGdkcFBlcmNhcCBzZWVtIHRvIG92ZXJhbGwgaGF2ZSBoaWdoZXIgbGlmZSBFeHBlY3RhbmN5Lg0KDQojIyMgTWFraW5nIGEgdGltZSBzZXJpZXMgcGxvdA0KDQpUaW1lIHNlcmllcyBwbG90cyBhcmUgYSBncmVhdCB3YXkgdG8gbG9vayBhdCB0aGUgZXZvbHV0aW9uIG9mIGEgcHJvY2VzcyB0aHJvdWdoIHRpbWUuIFdlIGNhbiB1c2UgYSB0aW1lIHNlcmllcyBwbG90IHRvIGFzayB0aGUgcXVlc3Rpb25zOg0KDQoxLiBIb3cgZG9lcyBHRFAgcGVyIGNhcGl0YSBjaGFuZ2Ugd2l0aCB0aW1lPw0KDQpgYGB7ciBUaW1lIHNlcmllcyBvZiBnZHAgcGVyIGNhcGl0YX0NCg0KZ2FwbWluZGVyICU+JQ0KICBmaWx0ZXIoY291bnRyeSAlaW4lIGMoIkNvbG9tYmlhIiwgIkNoaWxlIiwgIkFyZ2VudGluYSIsICJCcmF6aWwiLCAiUGVydSIsICJFY3VhZG9yIikpICU+JQ0KICBnZ3Bsb3QoKSArDQogICAgZ2VvbV9saW5lKG1hcHBpbmcgPSBhZXMoeCA9IHllYXIsIHkgPSBnZHBQZXJjYXAsIGNvbG91ciA9IGNvdW50cnkpKSArDQogICAgbGFicyh4ID0gIlllYXIiLCB5ID0gIkdEUCBQZXIgQ2FwaXRhIiwgY29sb3VyID0gIkNvdW50cnkiKSArDQogICAgeWxpbSgwLCAxNTAwMCkNCg0KDQpgYGANCg0KT3ZlcmFsbCBhbGwgdGhlIFNvdXRoIEFtZXJpY2FuIGNvdW50cnkncyBpbiB0aGUgcGxvdCBhYm92ZSBHRFAgcGVyIGNhcGl0YSBoYXZlIGluY3JlYXNlZCBvdmVyIHRpbWUuIEJ1dCBob3cgZG9lcyB0aGlzIGNvbXBhcmUgdG8gaG93IHRoZSBVSydzIGdkcCBwZXIgY2FwaXRhIGNoYW5nZWQ/DQoNCjIuIFdoaWNoIGNvdW50cnkncyBHRFAgcGVyIGNhcGl0YSByZWxhdGl2ZSB0byB0aGUgVUsgY2hhbmdlZCB0aGUgbW9zdCBvdmVyIHRpbWU/IFdoaWNoIGNoYW5nZWQgdGhlIGxlYXN0PyBXaGljaCBjb3VudHJ5J3MgcmVsYXRpdmUgR0RQIGluY3JlYXNlZCB0aGUgbW9zdCBmcm9tIHN0YXJ0IHRvIGZpbmlzaD8NCg0KYGBge3IgSG93IGRvZXMgcmVsYXRpdmUgZ2RwIHBlciBjYXBpdGEgY2hhbmdlIG92ZXIgdGltZSB9DQoNCmdhcG1pbmRlciAlPiUNCiAgZmlsdGVyKGNvdW50cnkgJWluJSBjKCJDb2xvbWJpYSIsICJDaGlsZSIsICJBcmdlbnRpbmEiLCAiQnJhemlsIiwgIlBlcnUiLCAiRWN1YWRvciIpKSAlPiUNCiAgZ2dwbG90KCkgKw0KICAgIGdlb21fbGluZShtYXBwaW5nID0gYWVzKHggPSB5ZWFyLCB5ID0gZ2RwUGVyY2FwX3JlbCwgY29sb3VyID0gY291bnRyeSkpICsNCiAgICBsYWJzKHggPSAiWWVhciIsIHkgPSAiR0RQIFBlciBDYXBpdGEgUmVsYXRpdmUgdG8gdGhlIFVLIiwgY29sb3VyID0gIkNvdW50cnkiKQ0KDQpgYGANCg0KMy4gV2hhdCdzIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBJbmZhbnQgTW9ydGFsaXR5IGFuZCBUaW1lPw0KDQpgYGB7ciBXaGF0IGlzIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBJbmZhbnQgTW9ydGFsaXR5IGFuZCBUaW1lfQ0KDQpnYXBtaW5kZXIgJT4lDQogIGZpbHRlcihjb3VudHJ5ICVpbiUgYygiQ29sb21iaWEiLCAiQ2hpbGUiLCAiQXJnZW50aW5hIiwgIkJyYXppbCIsICJQZXJ1IiwgIkVjdWFkb3IiKSkgJT4lDQogIGdncGxvdCgpICsNCiAgICBnZW9tX2xpbmUobWFwcGluZyA9IGFlcyh4ID0geWVhciwgeSA9IGluZmFudF9tb3J0YWxpdHksIGNvbG91ciA9IGNvdW50cnkpKSArIA0KICAgIHlsaW0oMCwgMTUwKSArDQogICAgbGFicyh5ID0gIkluZmFudCBNb3J0YWxpdHkiLCB4ID0gIlllYXIiLCBjb2xvdXIgPSAiQ291bnRyeSIpDQoNCmBgYA0KDQo0LiBXaGF0IGlzIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBmZXJ0aWxpdHkgYW5kIHRpbWU/DQoNCldoYXQga2luZCBvZiB0cmVuZHMgY2FuIHlvdSBwaWNrIG91dCB0aHJvdWdoIHRpbWU/IFdoaWNoIGNvdW50cnkncyBmZXJ0aWxpdHkgZHJvcHBlZCB0aGUgZmFzdGVzdD8gV2hpY2ggY291bnRyeSdzIGZlcnRpbGl0eSBjaGFuZ2VkIHRoZSBsZWFzdD8gV2hlbiBkbyB3ZSBzdGFydCB0byBoYXZlIGRhdGEgZm9yIGZlcnRpbGl0eSBmcm9tIHRoZXNlIGNvdW50cmllcz8NCg0KDQpgYGB7ciBXaGF0IGlzIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBmZXJ0aWxpdHkgYW5kIHRpbWV9DQoNCmdhcG1pbmRlciAlPiUNCiAgZmlsdGVyKGNvdW50cnkgJWluJSBjKCJDb2xvbWJpYSIsICJDaGlsZSIsICJBcmdlbnRpbmEiLCAiQnJhemlsIiwgIlBlcnUiLCAiRWN1YWRvciIpKSAlPiUNCiAgZ2dwbG90KCkgKw0KICAgIGdlb21fbGluZShtYXBwaW5nID0gYWVzKHggPSB5ZWFyLCB5ID0gZmVydGlsaXR5LCBjb2xvdXIgPSBjb3VudHJ5KSkgKyANCiAgICB5bGltKDAsIDEwKSArDQogICAgbGFicyh5ID0gIkZlcnRpbGl0eSIsIHggPSAiWWVhciIsIGNvbG91ciA9ICJDb3VudHJ5IikgKw0KICAgIGdndGl0bGUoIkZlcnRpbGl0eSBvdmVyIFRpbWUiKQ0KDQoNCmBgYA0KDQojIyMgKipFeGVyY2lzZXM6KioNCg0KMS4gUnVuIHRoZSBmb2xsb3dpbmcgbGluZXMgb2YgY29kZSB0byBtYWtlIHRoZSBwbG90IGJlbG93LiBBZGQgdGhlIHRpdGxlICJMaWZlIEV4cGVjdGFuY3kgaW4gdGhlIEFtZXJpY2FzIDE5NTIgdnMgMjAwNyIgdXNpbmcgYGdndGl0bGUoKWAuDQoNCmBgYHtyIExpZmUgZXhwZWN0YW5jeSBpbiB0aGUgQW1lcmljYXMgMTk1MiB2cyAyMDA3fQ0KDQpnYXBtaW5kZXIgJT4lDQogIGZpbHRlcihjb250aW5lbnQgPT0gIkFtZXJpY2FzIiwgeWVhciAlaW4lIGMoMTk1MiwgMjAwNykpICU+JQ0KICBtdXRhdGUoeWVhciA9IGFzLmZhY3Rvcih5ZWFyKSkgJT4lDQogIGdncGxvdCgpICsNCiAgICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeSA9IGNvdW50cnksIHggPSBsaWZlRXhwLCBjb2xvdXIgPSB5ZWFyKSkgKw0KICAgIGxhYnMoeCA9ICJMaWZlIEV4cGVjdGFuY3kiLCB5ID0gIkNvdW50cnkiLCBjb2xvdXIgPSAiWWVhciIpDQoNCmBgYA0KDQoyLiBUaGUgcGxvdCBiZWxvdyBzaG93cyB0aGUgZGlmZmVyZW5jZSBpbiBsaWZlIGV4cGVjdGFuY3kgZm9yIHRoZSAxMCBjb3VudHJpZXMgd2l0aCB0aGUgbGFyZ2VzdCBkaWZmZXJlbmNlLiANCg0KKiBDaGFuZ2UgdGhlIHggPSBmY3RfcmVvcmRlcihjb3VudHJ5LCBsaWZlX2V4cF9kaWZmKSB0byB4ID0gY291bnRyeS4gV2hhdCBkb2VzIGZjdF9yZW9yZGVyIGRvPyBUYWtlIGEgbG9vayBhdCA/ZmN0X3Jlb3JkZXIgZm9yIG1vcmUgaW5mby4gDQoNCiogUmVydW4gdGhlIHBsb3QsIHRoaXMgdGltZSByZW1vdmluZyBgY29vcmRfZmxpcCgpYC4gV2hhdCBkb2VzIHRoZSBmdW5jdGlvbiBgY29vcmRfZmxpcCgpYCBjaGFuZ2UgaW4gdGhlIHBsb3Q/DQoNCmBgYHtyIFdoYXQgZG9lcyBmY3RfcmVvcmRlciBhbmQgY29vcmRfZmxpcCBkb30NCg0KZ2FwX2xpZmVFeHBkaWZmX2RmIDwtIGdhcG1pbmRlciAlPiUNCiAgZ3JvdXBfYnkoY291bnRyeSkgJT4lIA0KICBzdW1tYXJpc2UobGlmZV9leHBfZGlmZiA9IG1heChsaWZlRXhwKSAtIG1pbihsaWZlRXhwKSkgJT4lIA0KICB0b3BfbihuID0gMTApDQoNCnAxIDwtIGdncGxvdChnYXBfbGlmZUV4cGRpZmZfZGYpICsNCiAgICBnZW9tX2NvbChtYXBwaW5nID0gYWVzKHggPSBmY3RfcmVvcmRlcihjb3VudHJ5LCBsaWZlX2V4cF9kaWZmKSwgeSA9IGxpZmVfZXhwX2RpZmYpLCBmaWxsID0gImJsdWUiKSArDQogICAgbGFicyh5ID0gIkRpZmZlcmVuY2UgaW4gTWF4aW11bSBhbmQgTWluaW11bSBMaWZlIEV4cGVjdGFuY3kgKHllYXJzKSIsIHggPSAiIikgKw0KICAgIGdndGl0bGUoIkRpZmZlcmVuY2UgaW4gTWF4aW11bSBhbmQgTWluaW11bSBMaWZlIEV4cGVjdGFuY3kiLCBzdWIgPSAiVG9wIDEwIGNvdW50cmllcyB3aXRoIHRoZSBsYXJnZXN0IGRpZmZlcmVuY2UgKDE5NTItMjAwNykiKSArDQogICAgeWxpbSgwLCA0MCkNCg0KcDEgKyBjb29yZF9mbGlwKCkNCg0KYGBgDQoNCg0KMy4gVHJ5IHJlY3JlYXRpbmcgdGhlIGZvbGxvd2luZyBwbG90IGJ5IGZpbGxpbmcgaW4gdGhlIGJsYW5rcyBiZWxvdw0KDQohW10ocGljdHVyZXMvUG9wdWxhdGlvbl9ieV95ZWFyLnBuZyl7d2lkdGg9NjUwcHh9DQoNCmBgYHtyIFJlcHJvZHVjZSB0aGUgcG9wdWxhdGlvbiBieSB5ZWFyIHBsb3QsIGV2YWwgPSBGQUxTRX0NCg0KZ2FwbWluZGVyICU+JQ0KICBmaWx0ZXIoY291bnRyeSAlaW4lIGMoPEJMQU5LPikpICU+JQ0KICBzZWxlY3QoeWVhciwgcG9wLCBjb3VudHJ5KSAlPiUNCiAgbXV0YXRlKHBvcCA9IHBvcC8xMDAwMDAwKSAlPiUNCiAgZ2dwbG90KCkgKw0KICAgIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gPEJMQU5LPiwgeSA9IDxCTEFOSz4sIGNvbG91ciA9IDxCTEFOSz4pKSArDQogIGZhY2V0X3dyYXAoY291bnRyeSB+IC4pICsNCiAgZ2d0aXRsZSgiUG9wdWxhdGlvbiBpbiBBcmdlbnRpbmEsIENoaWxlLCBQZXJ1LCBhbmQgVXJ1Z3VheSIpICsNCiAgbGFicyh4ID0gIlllYXIiLCB5ID0gIlBvcHVsYXRpb24gaW4gTWlsbGlvbnMiLCBjb2xvdXIgPSAiQ291bnRyeSIpDQoNCiAgDQpgYGANCg0KDQoqKkJvbnVzKioNCg0KNC4gQ2hhbmdlIHRoZSBwbG90IHNvIGl0IHNob3dzIHRoZSBkaWZmZXJlbmNlIGluIGxpZmUgZXhwZWN0YW5jeSBmb3IgdGhlIDEwIGNvdW50cmllcyB3aXRoIHRoZSBzbWFsbGVzdCBkaWZmZXJlbmNlLg0KDQoqSGludDoqIFlvdSdsbCBuZWVkIHRvIGNoYW5nZSB0b3BfbigpLCB0YWtlIGEgbG9vayBhdCB0aGUgaGVscCBmaWxlIHVzaW5nID90b3BfbiBhbmQgcmVhZCB3aGF0IGl0IHNheXMgZm9yIHRoZSBhcmd1bWVudCBgbmAuDQoNCiogVXBkYXRlIHRoZSBzdWJ0aXRsZSBgc3ViID1gIHRvIHJlZmxlY3QgdGhhdCB3ZSdyZSBsb29raW5nIGF0IHRoZSBjb3VudHJpZXMgd2l0aCB0aGUgc21hbGxlc3QgZGlmZmVyZW5jZS4NCg0KYGBge3IgVXBkYXRlIHNvIHRoZSBwbG90IHNob3dzIGNvdW50cmllcyB3aXRoIHRoZSBzbWFsbGVzdCBkaWZmZXJlbmNlIGluIGxpZmUgRXhwZWN0YW5jeX0NCg0KZ2FwX2xpZmVFeHBkaWZmX2RmIDwtIGdhcG1pbmRlciAlPiUNCiAgZ3JvdXBfYnkoY291bnRyeSkgJT4lIA0KICBzdW1tYXJpc2UobGlmZV9leHBfZGlmZiA9IG1heChsaWZlRXhwKSAtIG1pbihsaWZlRXhwKSkgJT4lIA0KICB0b3BfbihuID0gMTApDQoNCnAxIDwtIGdncGxvdChnYXBfbGlmZUV4cGRpZmZfZGYpICsNCiAgICBnZW9tX2NvbChtYXBwaW5nID0gYWVzKHggPSBmY3RfcmVvcmRlcihjb3VudHJ5LCBsaWZlX2V4cF9kaWZmKSwgeSA9IGxpZmVfZXhwX2RpZmYpLCBmaWxsID0gImJsdWUiKSArDQogICAgbGFicyh5ID0gIkRpZmZlcmVuY2UgaW4gTWF4aW11bSBhbmQgTWluaW11bSBMaWZlIEV4cGVjdGFuY3kgKHllYXJzKSIsIHggPSAiIikgKw0KICAgIGdndGl0bGUoIkRpZmZlcmVuY2UgaW4gTWF4aW11bSBhbmQgTWluaW11bSBMaWZlIEV4cGVjdGFuY3kiLCBzdWIgPSAiVG9wIDEwIGNvdW50cmllcyB3aXRoIHRoZSBsYXJnZXN0IGRpZmZlcmVuY2UgKDE5NTItMjAwNykiKSArDQogICAgeWxpbSgwLCA0MCkNCg0KcDEgKyBjb29yZF9mbGlwKCkNCg0KYGBgDQoNCg0KDQo1LiBXaGF0J3MgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIEluZmFudCBNb3J0YWxpdHkgYW5kIFllYXIgYnkgY29udGluZW50PyBGaWxsIGluIHRoZSBibGFua3MgdG8gZmluZCBvdXQuIA0KDQpgYGB7ciBXaGF0IGlzIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBpbmZhbnQgbW9ydGFsaXR5IGFuZCB5ZWFyIGJ5IGNvbnRpbmVudCwgZXZhbCA9IEZBTFNFfQ0KDQpnYXBtaW5kZXIgJT4lDQogIGdncGxvdCgpICsNCiAgICBnZW9tX2xpbmUobWFwcGluZyA9IGFlcyh4ID0geWVhciwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IDxCTEFOSz4sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gY291bnRyeSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gPEJMQU5LPikpICsgDQogICAgbGFicyh5ID0gIkluZmFudCBNb3J0YWxpdHkiLCB4ID0gIlllYXIiLCBjb2xvdXIgPSAiQ29udGluZW50IikgKw0KICAgIGZhY2V0X3dyYXAoLiB+IDxCTEFOSz4pDQoNCg0KYGBgDQoNCjVhLiBGaWx0ZXIgdGhlIGRhdGEgdG8gZmluZCBvdXQgd2hpY2ggY291bnRyaWVzIGluIEV1cm9wZSBoYWQgYSBpbmZhbnQgbW9ydGFsaXR5IHJhdGUgZ3JlYXRlciB0aGFuIDYwPw0KDQpOLkIuIFlvdSBkbyBub3QgbmVlZCB0byBtYWtlIGEgcGxvdC4NCg0KYGBge3IgV2hpY2ggY291bnRyaWVzIGluIEV1cm9wZSBoYWQgYW4gaW5mYW50IG1vcnRhbGl0eSByYXRlIGdyZWF0ZXIgdGhhbiA2MCwgZXZhbCA9IEZBTFNFfQ0KDQpnYXBtaW5kZXIgJT4lIA0KICBmaWx0ZXIoY29udGluZW50ID09ICJFdXJvcGUiLCBpbmZhbnRfbW9ydGFsaXR5ID4gPEJMQU5LPikNCg0KYGBgDQoNCg0KNS4gUnVuIHRoZSBjb2RlIGJlbG93IGFuZCB0YWtlIGEgbG9vayBhdCB0aGUgcGxvdCBvZiB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gbGlmZSBleHBlY3RhbmN5IGFuZCB5ZWFyIGJ5IGNvbnRpbmVudC4gVXNlIHRoZSB0aWR5dmVyc2UgdmVyYnMgdG8gZmlndXJlIG91dCB3aGljaCBjb3VudHJpZXMgYXJlIHJlcHJlc2VudGVkIGJ5IHRoZSBkaXBzIGluIEFmcmljYSAoMTk5MHMpIGFuZCBBc2lhICgxOTcwcykuDQoNCmBgYHtyIExpZmUgZXhwZWN0YW5jeSBieSB5ZWFyIGJ5IGNvbnRpbmVudH0NCg0KZ2FwbWluZGVyICU+JQ0KICBnZ3Bsb3QoKSArDQogICAgZ2VvbV9saW5lKG1hcHBpbmcgPSBhZXMoeCA9IHllYXIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBsaWZlRXhwLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cCA9IGNvdW50cnksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IGNvbnRpbmVudCkpICsgDQogICAgeWxpbSgwLCAxMDApICsNCiAgICBsYWJzKHkgPSAiTGlmZSBFeHBlY3RhbmN5IiwgeCA9ICJZZWFyIiwgY29sb3VyID0gIkNvbnRpbmVudCIpICsNCiAgICBmYWNldF93cmFwKGNvbnRpbmVudCB+IC4pDQoNCmBgYA0KDQoNCldoaWNoIGNvdW50cnkgaXMgcmVwcmVzZW50ZWQgaW4gdGhlIGRpcCBpbiBBZnJpY2E/DQoNCmBgYHtyfQ0KDQpgYGANCg0KV2hpY2ggY291bnRyeSBpcyByZXByZXNlbnRlZCBpbiB0aGUgZGlwIGluIEFzaWE/DQoNCmBgYHtyfQ0KDQpgYGANCg0KIyBHZXR0aW5nIEhlbHANCg0KMS4gKipIZWxwIGFuZCBWaWduZXR0ZSoqIENoZWNrIHRoZSBmdW5jdGlvbiBvciB0aGUgZG9jdW1lbnRhdGlvbiBvZiB0aGUgcGFja2FnZSB5b3UncmUgd29ya2luZyB3aXRoIHVzaW5nIHRoZSBoZWxwIGZ1bmN0aW9uIGA/YCBvciBgdmlnbmV0dGVgIHJlc3BlY3RpdmVseS4gDQoNCmBgYHtyIEdldHRpbmcgaGVscDogaGVscCBhbmQgdmlnbmV0dGUsIGV2YWwgPSBGQUxTRX0NCj9maWx0ZXINCg0KdmlnbmV0dGUoImRwbHlyIikNCmBgYA0KDQoyLiAqKkNSQU4gVGFzayBWaWV3KiogTG9va2luZyBmb3IgYSBwYWNrYWdlIHRvIGNhcnJ5IG91dCBhIHBhcnRpY3VsYXIgYW5hbHlzaXM/IENoZWNrIG91dCBbQ1JBTiBUYXNrIFZpZXddKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi92aWV3cy8pDQoNCjMuICoqU3RhY2sgT3ZlcmZsb3cqKiBbU3RhY2sgT3ZlcmZsb3ddKGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zL3RhZ2dlZC9yKSBDaGVjayBvdXQgU3RhY2sgT3ZlcmZsb3cuIFRoaXMgaXMgb25lIG9mIHRoZSBmaXJzdCBjYWxscyB3aGVyZSBtZW1iZXJzIGZyb20gdGhlIFIgQ29tbXVuaXR5IHdpbGwgaGVscCB5b3UgYW5zd2VyIHF1ZXN0aW9ucy4gDQoNCjQuICoqQ2hlYXRzaGVldHMqKiBNYW55IG9mIHRoZSB0aWR5dmVyc2UgcGFja2FnZXMgY29tZSB3aXRoIHRoZWlyIG93biBbY2hlYXRzaGVldHNdKGh0dHBzOi8vcnN0dWRpby5jb20vcmVzb3VyY2VzL2NoZWF0c2hlZXRzLyksIHdoaWNoIGFyZSBhIHF1aWNrIHJlZmVyZW5jZSBvbiBob3cgdG8gdXNlIHZhcmlvdXMgZnVuY3Rpb25zLiBJdCBhbHNvIGdpdmVzIGEgZ29vZCBvdmVydmlldyBvZiB3aGF0IGZ1bmN0aW9ucyBhcmUgYXZhaWxhYmxlLg0KDQohW10ocGljdHVyZXMvZGF0YS10cmFuc2Zvcm1hdGlvbi1jaGVhdC1zaGVldC5wbmcpe3dpZHRoPTM1MHB4fQ0KDQoNCg0KNS4gKipHb29nbGUuKiogR29vZ2xlIGlzIHlvdXIgZnJpZW5kISBUeXBlICJSIGhlbHAiIGZvbGxvd2VkIGJ5IHRoZSB3YXJuaW5nIG9yIGVycm9yIG1lc3NhZ2UgeW91IHJlY2VpdmVkIGFuZCBJIGd1YXJhbnRlZSB0aGVyZSB3aWxsIGJlIHNvbWVvbmUgd2hvIGhhcyBoYWQgdGhpcyBwcm9ibGVtIGJlZm9yZS4gDQoNCjYuICoqTWVldCB1cHMgYW5kIGNvZGluZyBjbHVicyoqIEpvaW4gYSBtZWV0IHVwIG9yIGNvZmZlZSBhbmQgY29kZSBncm91cC4gQ2hlY2sgb3V0IFItTGFkaWVzLiANCg0KNy4gKipGdXJ0aGVyIHJlc291cmNlcyoqIExvb2tpbmcgdG8gZGV2ZWxvcCB5b3VyIGxlYXJuaW5nIGZ1cnRoZXI/IENoZWNrIG91dCBteSBbdHJlbGxvIGJvYXJkXShodHRwczovL3RyZWxsby5jb20vYi91a0FwOXNVZy9yLXJlc291cmNlcy1mb3ItZGF0YS1zY2llbmNlKSBvbiBSIFJlc291cmNlcyBmb3IgRGF0YSBTY2llbmNlLiBUaGlzIGlzIHN0aWxsIGEgd29yayBpbiBwcm9ncmVzcywgYnV0IEknbSBjb250aW51YWxseSB1cGRhdGluZyBpdCB3aXRoIHVzZWZ1bCByZXNvdXJjZXMuIA0KDQoNCiMgUmVmZXJlbmNlcw0KDQoqIENoYW5naW5nIFIgU3R1ZGlvIFNldHRpbmdzIGFuZCBPdmVydmlldyBvZiBSU3R1ZGlvIFBhbmVscyBbU3lkbmV5IFIgTGFkaWVzXShodHRwczovL3JsYWRpZXNzeWRuZXkub3JnL2NvdXJzZXMvcnlvdXdpdGhtZS8wMS1iYXNpY2Jhc2ljcy0xLykNCiogU2hvd2Nhc2luZyBSU3R1ZGlvIGZlYXR1cmVzLCBvdmVydmlldyBvZiBmdW5jdGlvbnMgdXNpbmcgYHNlcSgpYCBhcyBhbiBleGFtcGxlLiBbU3RhdCA1NDUgVW5pdmVyc2l0eSBvZiBCcml0aXNoIENvbHVtYmlhIEJsb2ddKHN0YXQ1NDUuY29tKSBieSBKZW5ueSBCcnlhbg0KKiBJbnRyb2R1Y3Rpb24gdG8gZ2dwbG90MiBhbmQgdGhlIGdyYW1tYXIgb2YgZ3JhcGhpY3MuIFtSIGZvciBEYXRhIFNjaWVuY2VdKGh0dHBzOi8vcjRkcy5oYWQuY28ubnovKSBieSBIYWRsZXkgV2lja2hhbSBhbmQgR2FycmV0IEdyb21lbHVuZC4NCg0KIyMgQWNrbm93bGVkZ2VtZW50cw0KDQpUaGFuayB5b3UgdG8gSmhhaSBHaGFnaGFkYSBmb3IgbGF5aW5nIHRoZSBmb3VuZGF0aW9uIGZvciB0aGUgSW50cm8gdG8gUiBjb3Vyc2UuIFRoYW5rcyB0byBBbmRyZXcgTWVlY2hhbiwgUmViZWNjYSBCcm93biwgRGF2aWQgQmVsbCwgYW5kIExld2lzIER1bm5lIGZvciBiZWluZyB0aGUgZ3VpbmVhIHBpZ3MgZm9yIHRoaXMgd29yay4gU3BlY2lhbCB0aGFua3MgdG8gUmViZWNjYSBCcm93biBmb3IgdGhlIGNvbW1lbnRzIGFuZCBmZWVkYmFjayBvbiB0aGUgY29udGVudC4NCg==